public override void Check(IEnumerable <ObjectId> selectedObjectIds) { if (!selectedObjectIds.Any()) { return; } // 1. Create a kd tree var database = Database; var allVertices = new List <CurveVertex>(); using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var objectId in selectedObjectIds) { var curve = transaction.GetObject(objectId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } var vertices = CurveUtils.GetDistinctVertices(curve, transaction); allVertices.AddRange(vertices.Select(it => new CurveVertex(it, objectId))); } transaction.Commit(); } var kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); // 3. Filter out points that on same curve var visited = new HashSet <CurveVertex>(); using (var tolerance = new SafeToleranceOverride(1E-5, 1E-5)) foreach (var curveVertex in allVertices) { if (visited.Contains(curveVertex)) { continue; } var nears = kdTree.NearestNeighbours(curveVertex.Point.ToArray(), _tolerance); var qualified = new List <CurveVertex>(); qualified.Add(curveVertex); foreach (var near in nears) { visited.Add(near); if (near.Point == curveVertex.Point) { continue; } qualified.Add(near); } if (qualified.Count > 1) { _nearVertices.Add(qualified); } } }
/// <summary> /// New check - start the settings dialog and check. /// </summary> /// <returns></returns> public bool NewMapCleanCheckWithDialog() { var dialog = DialogService.Instance.CreateDialog <ActionsSettingDialog>(null, _actionsSettingViewModel); var dialogResult = dialog.ShowDialog(); if (dialogResult == null || !dialogResult.Value) { return(false); } // Clear all check results first. ClearCheckResults(raiseEvent: true); // Will check all curves in model space. OnlyCheckPolyline = false; var selectedIds = PrepareObjectIdsForCheck(); if (selectedIds == null || !selectedIds.Any()) { DialogService.Instance.ShowMessageBox(_actionsSettingViewModel, "图形区没有实体可检查", "提示:", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); return(false); } // If breaking objects, we need to break all crosing objects first. if (_actionsSettingViewModel.ActionSelectVM.BreakCrossingObjects) { using (var toleranceSWitcher = new SafeToleranceOverride()) { var algorithm = new BreakCrossingObjectsQuadTree(Document.Editor); algorithm.Check(selectedIds); Document.Editor.WriteMessage("\n共找到{0}个交叉对象,开始打断...", algorithm.CrossingInfos.Count()); algorithm.Fix(eraseOld: true); Document.Editor.WriteMessage("\n打断所有交叉对象成功!\n"); } } // Create actions _executingActions.Clear(); foreach (var action in _actionsSettingViewModel.ActionSelectVM.CheckedItems) { _executingActions.Add(action.ActionType); } // After objects are broken, need to update selectedIds. if (_actionsSettingViewModel.ActionSelectVM.BreakCrossingObjects) { selectedIds = PrepareObjectIdsForCheck(); } NewCheckWithPrompt(selectedIds, "拓扑错误"); return(true); }
public static Dictionary <ObjectId, List <Point3d> > CalculateIntersection(IEnumerable <ObjectId> objectIds, bool includeInline, Database database) { IEnumerable <IntersectionInfo> intersections = null; // 调低计算精度,否则有些交叉因为精度问题算不出来 var oldTolerance = DoubleExtensions.STolerance; DoubleExtensions.STolerance = 1e-05; using (var tolerance = new SafeToleranceOverride(DoubleExtensions.STolerance)) using (var transaction = database.TransactionManager.StartTransaction()) { // Build curve bsp tree and search all intersections var curve2dBspBuilder = new Curve2dBspBuilder(objectIds, transaction); intersections = curve2dBspBuilder.SearchRealIntersections(includeInline: includeInline); transaction.Commit(); } // 恢复默认的计算精度值 DoubleExtensions.STolerance = oldTolerance; // Group intersections by object id. var group = new Dictionary <ObjectId, List <Point3d> >(); foreach (var intersection in intersections) { if (!group.ContainsKey(intersection.SourceId)) { group[intersection.SourceId] = new List <Point3d>(); } var points = group[intersection.SourceId]; if (!points.Contains(intersection.IntersectPoint)) { points.Add(intersection.IntersectPoint); } if (intersection.SourceId == intersection.TargetId) { continue; } if (!group.ContainsKey(intersection.TargetId)) { group[intersection.TargetId] = new List <Point3d>(); } points = group[intersection.TargetId]; if (!points.Contains(intersection.IntersectPoint)) { points.Add(intersection.IntersectPoint); } } return(group); }
protected override IEnumerable <CheckResult> CheckImpl(IEnumerable <ObjectId> selectedObjectIds) { var results = new List <ZeroAreaLoopCheckResult>(); var database = Document.Database; using (var switcher = new SafeToleranceOverride()) { using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var selectedObjectId in selectedObjectIds) { var dbObj = transaction.GetObject(selectedObjectId, OpenMode.ForRead); var curve = dbObj as Curve; if (curve == null || curve is Xline) // Xline will cause exception { continue; } bool isClosed = false; var polyline = curve as Polyline; var polyline2d = curve as Polyline2d; if (polyline != null) { isClosed = polyline.Closed; } else if (polyline2d != null) { isClosed = polyline2d.Closed; } if (!isClosed) { var startPoint = curve.StartPoint; var endPoint = curve.EndPoint; if (startPoint.IsEqualTo(endPoint)) { isClosed = true; } } if (isClosed && curve.Area.EqualsWithTolerance(0.0, 0.00001)) { var checkResult = new ZeroAreaLoopCheckResult(selectedObjectId, curve.StartPoint); results.Add(checkResult); } } transaction.Commit(); } } return(results); }
public override void Check(IEnumerable <ObjectId> selectedObjectIds) { if (!selectedObjectIds.Any()) { return; } var database = Editor.Document.Database; var group = CalculateIntersection(selectedObjectIds, true, database); // Check each intersection whether it's a missing vertex. // TODO: 用一个比较低的精度去比较一个交点是否是顶点 using (var tolerance = new SafeToleranceOverride(_tolerance, _tolerance)) using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var pair in group) { var curve = transaction.GetObject(pair.Key, OpenMode.ForRead) as Curve; if (curve == null) { continue; } var vertices = CurveUtils.GetDistinctVertices(curve, transaction); var noneVertexPoints = new List <Point3d>(); foreach (var point in pair.Value) { var ret = CheckPointIsVertex(vertices, point, transaction); if (!ret) { noneVertexPoints.Add(point); } } if (noneVertexPoints.Count > 0) { _missingVertexInfos.Add(new MissingVertexInfo() { PolylineId = pair.Key, Positions = noneVertexPoints }); } } transaction.Commit(); } }
public bool CheckAndFixAll(IEnumerable <ObjectId> ids) { var watch = Stopwatch.StartNew(); bool result = false; using (var switcher = new SafeToleranceOverride()) { result = CheckAndFixAllImpl(ids); } watch.Stop(); var elapseMs = watch.ElapsedMilliseconds; if (Document != null) { Document.Editor.WriteMessage("\n本次检查用时{0}毫秒\n", elapseMs); } return(result); }
public MapClean.Status Fix(CheckResult checkResult, out List <ObjectId> resultIds) { if (checkResult.SourceIds != null) { foreach (var sourceId in checkResult.SourceIds) { if (!sourceId.IsValid || sourceId.IsErased) { resultIds = new List <ObjectId>(); return(Status.Invalid); } } } using (var siwtcher = new SafeToleranceOverride()) { return(FixImpl(checkResult, out resultIds)); } }
public IEnumerable <CheckResult> Check(IEnumerable <ObjectId> selectedObjectIds) { var watch = Stopwatch.StartNew(); IEnumerable <CheckResult> result = null; using (var waitCursor = new WaitCursorSwitcher()) using (var switcher = new SafeToleranceOverride()) { result = CheckImpl(selectedObjectIds); } watch.Stop(); var elapseMs = watch.ElapsedMilliseconds; if (Document != null) { Document.Editor.WriteMessage("\n本次检查用时{0}毫秒\n", elapseMs); } return(result); }
public static void TestSearchMinimumPolygons() { var drawingDb = Application.DocumentManager.MdiActiveDocument.Database; var editor = Application.DocumentManager.MdiActiveDocument.Editor; editor.WriteMessage("\n选择一条或几条闭合曲线:\n"); var result = editor.GetSelection(); if (result.Status != PromptStatus.OK) { return; } var polylineids = result.Value.GetObjectIds(); using (var tolerance = new SafeToleranceOverride(null, null)) using (var transaction = drawingDb.TransactionManager.StartTransaction()) { var polylines = new List <Polyline>(); foreach (var polylineid in polylineids) { var polyline = transaction.GetObject(polylineid, OpenMode.ForRead) as Polyline; polylines.Add(polyline.Clone() as Polyline); } Dictionary <Curve, List <Curve> > replaced = null; var polygons = MinimalLoopSearcher2.SearchMinimalPolygons(polylines, out replaced); var modelspaceId = SymbolUtilityServices.GetBlockModelSpaceId(drawingDb); var modelspace = transaction.GetObject(modelspaceId, OpenMode.ForWrite) as BlockTableRecord; foreach (var polyline in polygons) { polyline.Layer = "dk"; polyline.Color = Color.FromColorIndex(ColorMethod.ByAci, 3); modelspace.AppendEntity(polyline); transaction.AddNewlyCreatedDBObject(polyline, true); } transaction.Commit(); } }
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); }