bool AnalyzePolygonsUnionable(List <Point3d> sourcePolygon, List <Point3d> targetPolygon, out List <Point3d> unionPolygon) { unionPolygon = sourcePolygon; var unionResult = MinimalLoopSearcher2.ClipperBoolean(new List <List <Point3d> >() { sourcePolygon }, new List <List <Point3d> >() { targetPolygon }, ClipType.ctUnion); if (unionResult.Count > 1) { if (unionResult.Count == 2) { if ((PolygonIncludeSearcher.AreIdenticalCoordinates(sourcePolygon, unionResult[0]) || PolygonIncludeSearcher.AreIdenticalCoordinates(sourcePolygon, unionResult[1]))) { return(false); } } unionResult = unionResult .OrderByDescending(it => ComputerGraphics.PolygonArea(it.ToArray())) .ToList(); var source = new List <List <Point3d> >() { unionResult[0] }; // 如果存在多于一个布尔运算结果的情况,需要分析他们是否有包含关系 for (int i = 1; i < unionResult.Count; i++) { var subUnionResult = MinimalLoopSearcher2.ClipperBoolean( source, new List <List <Point3d> >() { unionResult[i] }, ClipType.ctUnion); if (subUnionResult.Count > 1 || subUnionResult.Count <= 0) { return(false); } source = subUnionResult; } unionResult = source; } if (unionResult.Count != 1) { return(false); } unionPolygon = unionResult[0]; return(true); }
public static IEnumerable <KeyValuePair <CurveSegment, CurveSegment> > SearchNearSegments(IEnumerable <ObjectId> selectedObjectIds, double tolerance) { var segments = GetAllCurveSegments(selectedObjectIds, tolerance, onlyForClosedPolygon: true); var vertices = new List <CollisionVertex>(); foreach (var segment in segments) { var collisionVertices = segment.MiniBoundingBox.Select(it => new CollisionVertex() { Point = new Point3d(it.X, it.Y, 0.0), Segment = segment }); vertices.AddRange(collisionVertices); } // Create kd tree var kdTree = new CurveVertexKdTree <CollisionVertex>(vertices, it => it.Point.ToArray(), ignoreZ: true); // Use kd tree to check collision bounding box's intersection var segmentPairs = new HashSet <KeyValuePair <CurveSegment, CurveSegment> >(); foreach (var segment in segments) { var extents = segment.GetExtents(); if (extents == null) { continue; } var minPoint = extents.Value.MinPoint; var maxPoint = extents.Value.MaxPoint; var nearVertices = kdTree.BoxedRange(new double[] { minPoint.X, minPoint.Y, 0.0 }, new double[] { maxPoint.X, maxPoint.Y, 0.0 }); foreach (var collisionVertex in nearVertices) { if (collisionVertex.Segment.EntityId == segment.EntityId || segmentPairs.Contains(new KeyValuePair <CurveSegment, CurveSegment>(segment, collisionVertex.Segment)) || segmentPairs.Contains(new KeyValuePair <CurveSegment, CurveSegment>(collisionVertex.Segment, segment))) { continue; } var boundingBox = segment.MiniBoundingBox.ToList(); boundingBox.Add(segment.MiniBoundingBox[0]); if (!ComputerGraphics.IsInPolygon(boundingBox.ToArray(), new Point2d(collisionVertex.Point.X, collisionVertex.Point.Y), 4)) { continue; } segmentPairs.Add(new KeyValuePair <CurveSegment, CurveSegment>(segment, collisionVertex.Segment)); } } return(segmentPairs); }
private static bool HaveSomeTextsOnBottom(Polyline polyline, Database database) { var extent = polyline.GeometricExtents; var path = ExtentsToPoint2ds(extent); var textCount = 0; using (var transaction = database.TransactionManager.StartTransaction()) { var modelspaceId = SymbolUtilityServices.GetBlockModelSpaceId(database); var modelspace = (BlockTableRecord)transaction.GetObject(modelspaceId, OpenMode.ForRead); foreach (ObjectId objId in modelspace) { if (textCount >= 5) { break; } var entity = transaction.GetObject(objId, OpenMode.ForRead); var text = entity as DBText; var mtext = entity as MText; if (text == null && mtext == null) { continue; } if (!IsVisibleEntity(entity, transaction)) { continue; } Point3d textPosition; if (text != null) { textPosition = text.Position; } else { textPosition = mtext.Location; } var pos2d = new Point2d(textPosition.X, textPosition.Y); if (ComputerGraphics.IsInPolygon2(pos2d, path) == 1) { textCount++; } } transaction.Commit(); } return(textCount >= 5); }
private bool IsColinear(LineSegment2d source, LineSegment2d target) { var length = source.Length; if (length.EqualsWithTolerance(0.0)) { return(false); } var leftStart = ComputerGraphics.IsLeft(source.StartPoint, source.EndPoint, target.StartPoint) / length; var leftEnd = ComputerGraphics.IsLeft(source.StartPoint, source.EndPoint, target.EndPoint) / length; if (leftStart.EqualsWithTolerance(0.0) && leftEnd.EqualsWithTolerance(0.0)) { return(true); } return(false); }
private IEnumerable <IntersectionInfo> GetUnderShootIntersections2(IEnumerable <ObjectId> selectedObjectIds, IEnumerable <CurveVertex> danglingVertices, double tolerance, Transaction transaction) { if (danglingVertices == null || !danglingVertices.Any()) { return(new List <IntersectionInfo>()); } var intersectMap = new Dictionary <CurveVertex, List <CurveVertex> >(); var desireExtendTypes = new Dictionary <CurveVertex, ExtendType>(); foreach (var vertex in danglingVertices) { var curve = transaction.GetObject(vertex.Id, OpenMode.ForRead); var desiredExtend = CurveUtils.GetExtendType((Curve)curve, vertex.Point); desireExtendTypes[vertex] = desiredExtend; } // 创建一个kdtree var kdTree = new CurveVertexKdTree <CurveVertex>(danglingVertices, it => it.Point.ToArray(), ignoreZ: true); foreach (var objectId in selectedObjectIds) { var curve = transaction.GetObject(objectId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } // 预检 var curveExtents = curve.GeometricExtents; var vertices = kdTree.BoxedRange(curveExtents.MinPoint.ToArray(), curveExtents.MaxPoint.ToArray()); if (vertices == null || !vertices.Any()) { continue; } var segments = CurveUtils.GetSegment2dsOfCurve(curve, transaction); var segmentsForCollision = segments.Select(it => new CurveSegmentForCollision() { LineSegment = it, EntityId = objectId, MiniBoundingBox = CurveSegmentForCollision.CreateCollisionBoundingBox(it, tolerance) }); foreach (var curveSegmentForCollision in segmentsForCollision) { var extents = curveSegmentForCollision.GetExtents(); if (extents == null) { continue; } var minPoint = extents.Value.MinPoint; var maxPoint = extents.Value.MaxPoint; var nearVertices = kdTree.BoxedRange(new double[] { minPoint.X, minPoint.Y, 0.0 }, new double[] { maxPoint.X, maxPoint.Y, 0.0 }); if (!nearVertices.Any()) { continue; } var boundingBox = curveSegmentForCollision.MiniBoundingBox.ToList(); boundingBox.Add(curveSegmentForCollision.MiniBoundingBox[0]); foreach (var curveVertex in nearVertices) { if (!ComputerGraphics.IsInPolygon(boundingBox.ToArray(), new Point2d(curveVertex.Point.X, curveVertex.Point.Y), 4)) { continue; } var danglingCurve = (Curve)transaction.GetObject(curveVertex.Id, OpenMode.ForRead); var danglingSegment = GetExtendLineSegment(danglingCurve, curveVertex.Point, transaction); var danglineLine = new Line2d(danglingSegment.StartPoint, danglingSegment.EndPoint); var intersectPoints = danglineLine.IntersectWith(curveSegmentForCollision.LineSegment); if (intersectPoints == null || intersectPoints.Length <= 0) { continue; } var intersectPoint2D = intersectPoints[0]; var param = danglingSegment.GetParameterOf(intersectPoint2D); var extendType = CurveIntersectUtils.ParamToExtendTypeForLine(param); if (extendType != desireExtendTypes[curveVertex]) { continue; } var intersectPoint = new Point3d(intersectPoint2D.X, intersectPoint2D.Y, 0); var dist = (intersectPoint - curveVertex.Point).Length; if (dist.Larger(tolerance)) { continue; } List <CurveVertex> intersectList; intersectMap.TryGetValue(curveVertex, out intersectList); if (intersectList == null) { intersectList = new List <CurveVertex>(); intersectMap[curveVertex] = intersectList; } intersectList.Add(new CurveVertex(intersectPoint, curveSegmentForCollision.EntityId)); } } } // 分析交点 var result = new List <IntersectionInfo>(); foreach (var pair in intersectMap) { var vertex = pair.Key; var extendVertices = pair.Value; var nearest = extendVertices[0]; var nearsetDist = (nearest.Point - vertex.Point).Length; for (int i = 1; i < extendVertices.Count; i++) { var dist = (extendVertices[i].Point - vertex.Point).Length; if (dist < nearsetDist) { nearsetDist = dist; nearest = extendVertices[i]; } } result.Add(new IntersectionInfo(vertex.Id, desireExtendTypes[vertex], nearest.Id, ExtendType.None, nearest.Point)); } return(result); }
public static ApartmentContourInfo CalcContour(Document doc, IEnumerable <ObjectId> objectIdsList) { var newCreatedIds = new List <ObjectId>(); IEnumerable <ObjectId> curveIds = new List <ObjectId>(); IEnumerable <ObjectId> splitSourceIds = new List <ObjectId>(); List <ObjectId> duplicateIds = new List <ObjectId>(); using (var waitCursor = new WaitCursorSwitcher()) using (var tolerance = new SafeToleranceOverride()) { // 1. Break down all lines doc.Editor.WriteMessage("\n打断所有交叉线...\n"); var breakCrossingAlgorithm = new BreakCrossingObjectsQuadTree(doc.Editor); breakCrossingAlgorithm.Check(objectIdsList); var breakIdPairs = breakCrossingAlgorithm.Fix(eraseOld: false).ToList(); splitSourceIds = breakIdPairs.Select(it => it.Key); var checkIds = objectIdsList.Except(splitSourceIds).ToList(); foreach (var idPair in breakIdPairs) { newCreatedIds.AddRange(idPair.Value); checkIds.AddRange(idPair.Value); } // 2. Erase the duplcate curves doc.Editor.WriteMessage("\n排除重复线...\n"); var duplicateEraserAlgorithm = new DuplicateEntityEraserKdTree(doc.Editor, 0.0005); duplicateEraserAlgorithm.Check(checkIds); var crossingInfos = duplicateEraserAlgorithm.CrossingInfos; if (crossingInfos != null) { foreach (var curveCrossingInfo in crossingInfos) { checkIds.Remove(curveCrossingInfo.TargetId); duplicateIds.Add(curveCrossingInfo.TargetId); } // Deal with the source duplicate var groups = crossingInfos.GroupBy(it => it.TargetId); foreach (var g in groups) { if (g.Count() <= 1) { continue; } bool first = true; foreach (var curveCrossingInfo in g) { if (first) { first = false; continue; } checkIds.Remove(curveCrossingInfo.SourceId); duplicateIds.Add(curveCrossingInfo.SourceId); } } } // 3. Extend undershoot doc.Editor.WriteMessage("\n调整未及点...\n"); var extendUndershoots = new ExtendUnderShoots(doc.Editor, 0.001); extendUndershoots.Check(checkIds); var splittedIds = extendUndershoots.Fix(breakTarget: true); foreach (var pair in splittedIds) { checkIds.Remove(pair.Key); checkIds.AddRange(pair.Value); // Also recorded in newCreatedIds which will be removed at the end. if (newCreatedIds.Contains(pair.Key)) { newCreatedIds.Remove(pair.Key); newCreatedIds.AddRange(pair.Value); } } // 4. 排除0面积闭合线 doc.Editor.WriteMessage("\n排除零面积闭合线...\n"); var zeroAreaLoopIds = CurveUtils.GetZeroAreaLoop(checkIds, doc.Database); foreach (var zeroAreaLoopId in zeroAreaLoopIds) { checkIds.Remove(zeroAreaLoopId); duplicateIds.Add(zeroAreaLoopId); } // 5. 删除0长度对象 doc.Editor.WriteMessage("\n排除零长度对象...\n"); var zeroLengthEraser = new ZeroLengthEraser(doc.Editor); zeroLengthEraser.Check(checkIds); foreach (ObjectId zeroLengthId in zeroLengthEraser.ZerolengthObjectIdCollection) { checkIds.Remove(zeroLengthId); duplicateIds.Add(zeroLengthId); } curveIds = checkIds; //// Test code //using (var transaction = doc.Database.TransactionManager.StartTransaction()) //{ // var color = Color.FromColorIndex(ColorMethod.ByAci, 3); // Green // ObjectId layerId = LayerUtils.AddNewLayer(doc.Database, "temp-poly", "Continuous", color); // foreach (var polygonId in polygonIds) // { // var entity = (Entity)transaction.GetObject(polygonId, OpenMode.ForWrite); // entity.Color = color; // entity.LayerId = layerId; // } // transaction.Commit(); //} //return new List<Point2d>(); } // 2. Make polygons. doc.Editor.WriteMessage("开始分析外墙轮廓..."); var resultIds = new List <ObjectId>(); if (curveIds.Any()) { var color = Color.FromColorIndex(ColorMethod.ByAci, 3); // Green ObjectId layerId = LayerUtils.AddNewLayer(doc.Database, "temp-poly", "Continuous", color); using (var tolerance = new SafeToleranceOverride()) using (var waitCursor = new WaitCursorSwitcher()) { //var polygons = MinimalLoopSearcher2.Search(curveIds, doc); //using (var transaction = doc.Database.TransactionManager.StartTransaction()) //{ // var modelspaceId = SymbolUtilityServices.GetBlockModelSpaceId(doc.Database); // var modelspace = (BlockTableRecord)transaction.GetObject(modelspaceId, OpenMode.ForWrite); // foreach (var polyline in polygons) // { // polyline.Color = color; // polyline.LayerId = layerId; // var id = modelspace.AppendEntity(polyline); // resultIds.Add(id); // transaction.AddNewlyCreatedDBObject(polyline, true); // } // transaction.Commit(); //} resultIds = NtsUtils.PolygonizeLineStrings(doc.Database, curveIds, "temp-poly", color, 0.0001); } } // 3. Union all polygons var database = doc.Database; var partitioner = new DrawingPartitioner(database); partitioner.Check(resultIds); // 4. Get largest are polygon which is the apartment's contour var polylines = new List <Polyline>(); foreach (var region in partitioner.IsolatedRegions) { var polyline = new Polyline(region.Contour.Count); int i = 0; foreach (var point in region.Contour) { polyline.AddVertexAt(i++, new Point2d(point.X, point.Y), 0, 0, 0); } polyline.Closed = true; polylines.Add(polyline); } polylines.Sort((poly1, poly2) => { if (poly1.Area > poly2.Area) { return(-1); } return(1); }); if (polylines.Count >= 2) { var first = polylines[0]; var second = polylines[1]; // Exclude the situation if the largest polyline is a drawing frame. if (IsRectangle(first) && HaveSomeTextsOnBottom(first, database) && PolygonIncludeSearcher.IsInclude(first, second, null)) { polylines.RemoveAt(0); } } Polyline largestPolyline = polylines.FirstOrDefault(); var resultPoints = new List <Point2d>(); if (largestPolyline != null) { resultPoints = CurveUtils.GetDistinctVertices2D(largestPolyline, null); if (resultPoints[0] != resultPoints[resultPoints.Count - 1]) { resultPoints.Add(resultPoints[0]); } var clockwise = ComputerGraphics.ClockWise2(resultPoints.ToArray()); if (clockwise) { resultPoints.Reverse(); } //// Test code ! //using (var transaction = database.TransactionManager.StartTransaction()) //{ // var modelspaceId = SymbolUtilityServices.GetBlockModelSpaceId(database); // var modelspace = (BlockTableRecord)transaction.GetObject(modelspaceId, OpenMode.ForWrite); // var color = Color.FromColorIndex(ColorMethod.ByAci, 3); // Green // ObjectId layerId = LayerUtils.AddNewLayer(doc.Database, "temp-poly", "Continuous", color); // largestPolyline.Color = color; // largestPolyline.LayerId = layerId; // modelspace.AppendEntity(largestPolyline); // transaction.AddNewlyCreatedDBObject(largestPolyline, add: true); // foreach (var polyline in polylines) // { // if (polyline == largestPolyline) // continue; // polyline.Color = color; // polyline.LayerId = layerId; // modelspace.AppendEntity(polyline); // transaction.AddNewlyCreatedDBObject(polyline, add: true); // } // transaction.Commit(); //} } // Get contour linesegments from resultPoints var contourSegments = new List <LineSegment3d>(); var innerSegments = new List <LineSegment3d>(); if (resultPoints.Count > 0) { for (var i = 0; i < resultPoints.Count - 1; i++) { var start = new Point3d(resultPoints[i].X, resultPoints[i].Y, 0); var end = new Point3d(resultPoints[i + 1].X, resultPoints[i + 1].Y, 0); var segment = new LineSegment3d(start, end); contourSegments.Add(segment); } // Get inner linesegments using (var tr = doc.Database.TransactionManager.StartTransaction()) { var contourArray = resultPoints.ToArray(); foreach (var objId in curveIds) { var point2ds = CurveUtils.GetDistinctVertices2D(objId, tr); for (var i = 0; i < point2ds.Count - 1; i++) { var start = point2ds[i]; var end = point2ds[i + 1]; if (start.IsEqualTo(end)) { continue; } // TODO: no need to calculate again for startInPoly. var startInPoly = ComputerGraphics.IsInPolygon2(start, contourArray); var endInPoly = ComputerGraphics.IsInPolygon2(end, contourArray); if ((startInPoly == 0 && endInPoly == 0) || (startInPoly == -1 && endInPoly == -1)) { continue; } var segment = new LineSegment3d(new Point3d(start.X, start.Y, 0), new Point3d(end.X, end.Y, 0)); innerSegments.Add(segment); } } tr.Commit(); } } // 5. Delete the polygons of resultIds using (var tr = doc.Database.TransactionManager.StartTransaction()) { foreach (var objId in resultIds) { if (objId.IsErased) { continue; } var dbObj = tr.GetObject(objId, OpenMode.ForWrite); dbObj.Erase(); } //////////////////////////////////////////////////////////////////////////////////////// tr.Commit(); } // Delete the splited curves using (var tr = doc.Database.TransactionManager.StartTransaction()) { foreach (var newCreatedId in newCreatedIds) { if (newCreatedId.IsErased) { continue; } var dbObj = tr.GetObject(newCreatedId, OpenMode.ForWrite); dbObj.Erase(); } //////////////////////////////////////////////////////////////////////////////////////// tr.Commit(); } var result = new ApartmentContourInfo() { Contour = contourSegments, InternalSegments = innerSegments }; return(result); }
public override void Check(IEnumerable <Autodesk.AutoCAD.DatabaseServices.ObjectId> selectedObjectIds) { if (!selectedObjectIds.Any()) { return; } var precision = 0.000001; // First we need to make sure all intersections are vertices of polygon var missingVertexSearcher = new MissingVertexSearcherQuadTree(Editor); missingVertexSearcher.Check(selectedObjectIds); if (missingVertexSearcher.MissingVertexInfos.Any()) { missingVertexSearcher.FixAll(); } // Use clipper to search holes var subject = new List <List <IntPoint> >(1); var clipper = new List <List <IntPoint> >(1); var database = Editor.Document.Database; Extents3d extents = new Extents3d(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); bool first = true; // Use all polygons to make up clipper. using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var objId in selectedObjectIds) { var curve = transaction.GetObject(objId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } if (!IsCurveClosed(curve)) { continue; } // Calculate its extents. if (first) { extents = curve.GeometricExtents; first = false; } else { extents.AddExtents(curve.GeometricExtents); } // Add it to the clipper. var vertices = CurveUtils.GetDistinctVertices2D(curve, transaction); // Only for polygon. if (vertices.Count() < 3) { continue; } // That has the same vertex for the first and last array members. if (vertices[0] != vertices[vertices.Count - 1]) { vertices.Add(vertices[0]); } var clockwise = ComputerGraphics.ClockWise2(vertices.ToArray()); if (!clockwise) { vertices.Reverse(); } if (vertices[0] == vertices[vertices.Count - 1]) { vertices.RemoveAt(vertices.Count - 1); } clipper.Add(vertices.Select(it => new IntPoint(it.X / precision, it.Y / precision)).ToList()); } transaction.Commit(); } // Create subject rectangle. var vector = (extents.MaxPoint - extents.MinPoint) * 0.1; var minPoint = extents.MinPoint - vector; var maxPoint = extents.MaxPoint + vector; subject.Add(new List <IntPoint>() { new IntPoint(minPoint.X / precision, minPoint.Y / precision), new IntPoint(minPoint.X / precision, maxPoint.Y / precision), new IntPoint(maxPoint.X / precision, maxPoint.Y / precision), new IntPoint(maxPoint.X / precision, minPoint.Y / precision) }); var result = new List <List <IntPoint> >(); var cpr = new Clipper(); cpr.AddPaths(subject, PolyType.ptSubject, true); cpr.AddPaths(clipper, PolyType.ptClip, true); cpr.Execute(ClipType.ctXor, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero); if (result.Count <= 0) { return; } foreach (var path in result) { // Ignore the outmost loop. if (path.Contains(new IntPoint(minPoint.X / precision, minPoint.Y / precision))) { continue; } var points = path.Select(it => new Point2d(it.X * precision, it.Y * precision)).ToList(); if (points[0] != points[points.Count - 1]) { points.Add(points[0]); } var array = points.ToArray(); if (ComputerGraphics.ClockWise2(array)) { continue; } var polyline = CreatePolygon(array); if (polyline.Area.Smaller(0.001)) { polyline.Dispose(); continue; } _holes.Add(polyline); } }