Untitled
unknown
plain_text
a year ago
10 kB
11
Indexable
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
public class LargestInscribedRect
{
// Provided Convex Hull Function (Assume it's implemented elsewhere)
public static List<Point2d> ComputeHull(List<Point2d> points, double concavity = 0.0, double scaleFactor = 2)
{
// Implementation of Concave Hull
// Assume this function is defined elsewhere and works correctly.
// Replace this with your actual implementation
// Placeholder: just return a simple rectangle for now
if (points.Count < 3) return points;
double minX = points.Min(p => p.X);
double minY = points.Min(p => p.Y);
double maxX = points.Max(p => p.X);
double maxY = points.Max(p => p.Y);
return new List<Point2d>
{
new Point2d(minX, minY),
new Point2d(maxX, minY),
new Point2d(maxX, maxY),
new Point2d(minX, maxY)
};
}
public static Polyline GetLargestRectangleInsidePolyline(Polyline polyline)
{
// 1. Preprocessing: Convex Hull
List<Point2d> polylinePoints = new List<Point2d>();
for (int i = 0; i < polyline.NumberOfVertices; i++)
{
polylinePoints.Add(polyline.GetPoint2dAt(i));
}
List<Point2d> hullPoints = ComputeHull(polylinePoints);
// 2. Rotating Calipers
Polyline largestRectangle = RotatingCalipers(hullPoints);
// 3. Clipping to Original Polygon
// Simplified approach: Check if rectangle is inside, otherwise shrink it
if (IsRectangleInsidePolygon(largestRectangle, polyline))
{
return largestRectangle;
}
else
{
return ShrinkRectangleToFit(largestRectangle, polyline);
}
}
private static Polyline RotatingCalipers(List<Point2d> hullPoints)
{
if (hullPoints.Count < 3)
{
// Handle cases where the hull has fewer than 3 points (e.g., a point or a line segment)
if (hullPoints.Count == 2)
{
Polyline linePolyline = new Polyline();
linePolyline.AddVertexAt(0, hullPoints[0], 0, 0, 0);
linePolyline.AddVertexAt(1, hullPoints[1], 0, 0, 0);
return linePolyline;
}
else
{
return null; // Or handle as appropriate for your application
}
}
double minX = hullPoints.Min(p => p.X);
double minY = hullPoints.Min(p => p.Y);
double maxX = hullPoints.Max(p => p.X);
double maxY = hullPoints.Max(p => p.Y);
Point2d p1 = new Point2d(minX, minY);
Point2d p2 = new Point2d(maxX, minY);
Point2d p3 = new Point2d(maxX, maxY);
Point2d p4 = new Point2d(minX, maxY);
Polyline maxRect = new Polyline();
maxRect.AddVertexAt(0, p1, 0, 0, 0);
maxRect.AddVertexAt(1, p2, 0, 0, 0);
maxRect.AddVertexAt(2, p3, 0, 0, 0);
maxRect.AddVertexAt(3, p4, 0, 0, 0);
maxRect.Closed = true;
double maxArea = (maxX - minX) * (maxY - minY);
double angleIncrement = 0.01; // Adjust for finer/coarser rotation
for (double angle = 0; angle < Math.PI / 2; angle += angleIncrement)
{
List<Point2d> rotatedHull = hullPoints.Select(p => RotatePoint(p, angle, new Point2d((minX + maxX) / 2, (minY + maxY) / 2))).ToList();
minX = rotatedHull.Min(p => p.X);
minY = rotatedHull.Min(p => p.Y);
maxX = rotatedHull.Max(p => p.X);
maxY = rotatedHull.Max(p => p.Y);
Point2d rotatedP1 = new Point2d(minX, minY);
Point2d rotatedP2 = new Point2d(maxX, minY);
Point2d rotatedP3 = new Point2d(maxX, maxY);
Point2d rotatedP4 = new Point2d(minX, maxY);
// Rotate the points back to the original coordinate system
p1 = RotatePoint(rotatedP1, -angle, new Point2d((minX + maxX) / 2, (minY + maxY) / 2));
p2 = RotatePoint(rotatedP2, -angle, new Point2d((minX + maxX) / 2, (minY + maxY) / 2));
p3 = RotatePoint(rotatedP3, -angle, new Point2d((minX + maxX) / 2, (minY + maxY) / 2));
p4 = RotatePoint(rotatedP4, -angle, new Point2d((minX + maxX) / 2, (minY + maxY) / 2));
double area = (maxX - minX) * (maxY - minY);
if (area > maxArea)
{
maxArea = area;
maxRect.SetPointAt(0, p1);
maxRect.SetPointAt(1, p2);
maxRect.SetPointAt(2, p3);
maxRect.SetPointAt(3, p4);
}
}
return maxRect;
}
// Helper function to rotate a point around a center
private static Point2d RotatePoint(Point2d point, double angle, Point2d center)
{
double x = center.X + (point.X - center.X) * Math.Cos(angle) - (point.Y - center.Y) * Math.Sin(angle);
double y = center.Y + (point.X - center.X) * Math.Sin(angle) + (point.Y - center.Y) * Math.Cos(angle);
return new Point2d(x, y);
}
// Function to shrink the rectangle until it fits inside the polygon
private static Polyline ShrinkRectangleToFit(Polyline rectangle, Polyline polygon)
{
double scaleFactor = 0.95; // Shrink by 5% each iteration
int maxIterations = 20; // Prevent infinite loop
int iteration = 0;
while (!IsRectangleInsidePolygon(rectangle, polygon) && iteration < maxIterations)
{
rectangle = ScaleRectangle(rectangle, scaleFactor);
iteration++;
}
return rectangle;
}
// Helper function to check if a rectangle is fully inside a polygon
private static bool IsRectangleInsidePolygon(Polyline rectangle, Polyline polygon)
{
for (int i = 0; i < rectangle.NumberOfVertices; i++)
{
Point2d point = rectangle.GetPoint2dAt(i);
if (!IsPointInsidePolygon(point, polygon))
{
return false;
}
}
return true;
}
// Helper function to check if a point is inside a polygon using ray casting
private static bool IsPointInsidePolygon(Point2d point, Polyline polygon)
{
int i, j;
bool c = false;
for (i = 0, j = polygon.NumberOfVertices - 1; i < polygon.NumberOfVertices; j = i++)
{
Point2d pi = polygon.GetPoint2dAt(i);
Point2d pj = polygon.GetPoint2dAt(j);
if (((pi.Y > point.Y) != (pj.Y > point.Y)) &&
(point.X < (pj.X - pi.X) * (point.Y - pi.Y) / (pj.Y - pi.Y) + pi.X))
{
c = !c;
}
}
return c;
}
// Helper function to scale a rectangle from its center
private static Polyline ScaleRectangle(Polyline rectangle, double scaleFactor)
{
// Calculate the center of the rectangle
Point2d center = CalculateRectangleCenter(rectangle);
// Scale each vertex from the center
Polyline scaledRectangle = new Polyline();
for (int i = 0; i < rectangle.NumberOfVertices; i++)
{
Point2d vertex = rectangle.GetPoint2dAt(i);
Point2d scaledVertex = new Point2d(
center.X + (vertex.X - center.X) * scaleFactor,
center.Y + (vertex.Y - center.Y) * scaleFactor
);
scaledRectangle.AddVertexAt(i, scaledVertex, 0, 0, 0);
}
scaledRectangle.Closed = true;
return scaledRectangle;
}
// Helper function to calculate the center of a rectangle
private static Point2d CalculateRectangleCenter(Polyline rectangle)
{
double centerX = 0;
double centerY = 0;
for (int i = 0; i < rectangle.NumberOfVertices; i++)
{
Point2d vertex = rectangle.GetPoint2dAt(i);
centerX += vertex.X;
centerY += vertex.Y;
}
return new Point2d(centerX / rectangle.NumberOfVertices, centerY / rectangle.NumberOfVertices);
}
[CommandMethod("FindLargestRectangle")]
public void FindLargestRectangleCommand()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: ");
peo.SetRejectMessage("\nInvalid selection. Please select a polyline.");
peo.AddAllowedClass(typeof(Polyline), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
{
ed.WriteMessage("\nNo polyline selected.");
return;
}
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
Polyline polyline = tr.GetObject(per.ObjectId, OpenMode.ForRead) as Polyline;
if (polyline != null)
{
Polyline largestRect = LargestInscribedRect.GetLargestRectangleInsidePolyline(polyline);
if (largestRect != null)
{
// Add the resulting rectangle to the drawing
BlockTable bt = tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
btr.AppendEntity(largestRect);
tr.AddNewlyCreatedDBObject(largestRect, true);
tr.Commit();
}
else
{
ed.WriteMessage("\nCould not find a valid rectangle.");
}
}
else
{
ed.WriteMessage("\nSelected object is not a polyline.");
}
}
}
}Editor is loading...
Leave a Comment