private IEnumerable <IntersectionInfo> GetApparentIntersectionsKdTree(IEnumerable <CurveVertex> danglingVertices, Transaction transaction) { // Create a KDTree for dangling vertices. var result = new List <IntersectionInfo>(); var visitedPairs = new Dictionary <CurveVertex, CurveVertex>(); var kdTree = new CurveVertexKdTree <CurveVertex>(danglingVertices, it => it.Point.ToArray(), ignoreZ: true); foreach (var danglingVertex in danglingVertices) { var neighbors = kdTree.NearestNeighbours(danglingVertex.Point.ToArray(), _tolerance * 2.0); if (!neighbors.Any()) { continue; } foreach (var neighbor in neighbors) { if (visitedPairs.ContainsKey(neighbor)) { continue; } // Mark it as visited. visitedPairs[neighbor] = danglingVertex; var info = CalcApparentIntersection(danglingVertex, neighbor, transaction); if (info != null) { result.Add(info); } } } return(result); }
private void BuildCurveVertexKdTree(IEnumerable <ObjectId> allIds, Transaction transaction, out Dictionary <ObjectId, CurveVertex[]> curveVertices, out CurveVertexKdTree <CurveVertex> kdTree) { kdTree = null; curveVertices = new Dictionary <ObjectId, CurveVertex[]>(); var allVertices = new List <CurveVertex>(); foreach (var id in allIds) { var points = CurveUtils.GetCurveEndPoints(id, transaction); if (points.Length <= 0) { continue; } var distinctPoints = GetDistinctPoints(points); // If distinctPoints.Length == 1, means it's self-loop if (distinctPoints.Length <= 1) { continue; } var vertices = distinctPoints.Select(it => new CurveVertex(it, id)); curveVertices[id] = vertices.ToArray(); allVertices.AddRange(vertices); } kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); }
public override void Check(IEnumerable <ObjectId> selectedObjectIds) { if (selectedObjectIds == null || !selectedObjectIds.Any()) { return; } var watch = Stopwatch.StartNew(); var database = Editor.Document.Database; using (var transaction = database.TransactionManager.StartTransaction()) { //// Build a kd tree from all curve vertices. Dictionary <ObjectId, CurveVertex[]> curveVertices = null; CurveVertexKdTree <CurveVertex> kdTree = null; BuildCurveVertexKdTree(selectedObjectIds, transaction, out curveVertices, out kdTree); SearchDuplicateEntities(curveVertices, kdTree); //var kdTree = BuildCurveVertexKdTree2(selectedObjectIds, transaction); //SearchDuplicateEntities2(selectedObjectIds, kdTree, transaction); } watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; //Editor.WriteMessage("\n查找重复实体花费时间{0}毫秒", elapsedMs); }
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); } } }
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 void SearchDuplicateEntities2(IEnumerable <ObjectId> curveIds, CurveVertexKdTree <CurveVertex> kdTree, Transaction transaction) { var crossingInfos = new List <CurveCrossingInfo>(); var visited = new HashSet <KeyValuePair <ObjectId, ObjectId> >(); foreach (var id in curveIds) { var infos = SearchDuplicateEntities2(id, kdTree, visited, transaction); if (infos.Any()) { crossingInfos.AddRange(infos); } } _crossingInfos = crossingInfos; }
public IEnumerable <CurveVertex> Search() { var result = new List <CurveVertex>(); var visitedIds = new HashSet <ObjectId>(); var candidates = new Stack <CurveVertex>(); Dictionary <ObjectId, CurveVertex[]> curveVertices = null; CurveVertexKdTree <CurveVertex> kdTree = null; BuildCurveVertexKdTree(_allIds, _transaction, out curveVertices, out kdTree); var pendingIds = _allIds.Except(visitedIds).ToList(); while (pendingIds.Count > 0) { // 1. Arbitrary select a curve as the started curve foreach (ObjectId objId in pendingIds) { // Mark it as visited. visitedIds.Add(objId); // if it has vertex, break. if (curveVertices.ContainsKey(objId)) { foreach (var curveVertex in curveVertices[objId]) { candidates.Push(curveVertex); } break; } } // 2. Start popup the candidates and dispose them while (candidates.Count > 0) { var vertex = candidates.Pop(); var isDangling = CheckDangling(vertex, pendingIds, visitedIds, candidates, curveVertices, kdTree); if (isDangling) { result.Add(vertex); } } // Shrink the pending ids collection. pendingIds = pendingIds.Except(visitedIds).ToList(); } return(result); }
private IEnumerable <ClusterNodesInfo> GetClusterNodesKdTree(IEnumerable <CurveVertex> danglingVertices, Transaction transaction) { var result = new List <ClusterNodesInfo>(); var kdTree = new CurveVertexKdTree <CurveVertex>(danglingVertices, it => it.Point.ToArray(), ignoreZ: true); // Get all connections of kdTree foreach (var vertex in danglingVertices) { var neighbors = kdTree.NearestNeighbours(vertex.Point.ToArray(), _tolerance); if (!neighbors.Any()) { continue; } // Remove some invalid vertices. var list = neighbors.ToList(); int currentIndex = 0; while (currentIndex < list.Count - 1) { var current = list[currentIndex]; for (int i = currentIndex + 1; i < list.Count; i++) { var dist = current.Point.DistanceTo(list[i].Point); if (dist.Larger(_tolerance)) { list.RemoveAt(currentIndex); list.RemoveAt(i - 1); break; } } currentIndex++; } if (list.Count > 1) { var node = new ClusterNodesInfo() { Vertices = list.ToArray() }; result.Add(node); } } return(result); }
private IEnumerable <SEdge <CurveVertex> > GetEdges(IEnumerable <ObjectId> allIds, HashSet <ObjectId> visitedIds, Transaction transaction) { Dictionary <ObjectId, CurveVertex[]> curveVertices = null; CurveVertexKdTree <CurveVertex> kdTree = null; BuildCurveVertexKdTree(allIds, transaction, out curveVertices, out kdTree); var result = new List <SEdge <CurveVertex> >(); var candidates = new Stack <KeyValuePair <ObjectId, CurveVertex> >(); var pendingIds = allIds.Except(visitedIds).ToList(); while (pendingIds.Count > 0) { // 1. Arbitrary select a curve as the started curve foreach (ObjectId objId in pendingIds) { var edges = VisitCurve(null, objId, pendingIds, visitedIds, candidates, curveVertices, kdTree, transaction); if (edges.Any()) { result.AddRange(edges); break; } } // 2. Start popup the candidates and dispose them while (candidates.Count > 0) { var pair = candidates.Pop(); // There is the case that it has been visited, such as the last line in a loop. if (visitedIds.Contains(pair.Key)) { continue; } var edges = VisitCurve(pair.Value, pair.Key, pendingIds, visitedIds, candidates, curveVertices, kdTree, transaction); result.AddRange(edges); } // Shrink the pending ids collection. pendingIds = pendingIds.Except(visitedIds).ToList(); } return(result); }
CurveVertexKdTree <CurveVertex> CreatePolygonKdTree(IEnumerable <ObjectId> objectIds, Transaction transaction) { var vertices = new List <CurveVertex>(); foreach (var objectId in objectIds) { var points = CurveUtils.GetDistinctVertices(objectId, transaction); if (points[0] == points[points.Count - 1]) { points.RemoveAt(points.Count - 1); } vertices.AddRange(points.Select(it => new CurveVertex(it, objectId))); } var kdTree = new CurveVertexKdTree <CurveVertex>(vertices, it => it.Point.ToArray(), ignoreZ: true); return(kdTree); }
private CurveVertexKdTree <CurveVertex> BuildCurveVertexKdTree2(IEnumerable <ObjectId> allIds, Transaction transaction) { var allVertices = new List <CurveVertex>(); foreach (var id in allIds) { var points = CurveUtils.GetDistinctVertices(id, transaction); if (!points.Any()) { continue; } var vertices = points.Select(it => new CurveVertex(it, id)); allVertices.AddRange(vertices); } var kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); return(kdTree); }
private void BuildCurveVertexKdTree(IEnumerable <ObjectId> allIds, Transaction transaction, out Dictionary <ObjectId, CurveVertex[]> curveVertices, out CurveVertexKdTree <CurveVertex> kdTree) { curveVertices = new Dictionary <ObjectId, CurveVertex[]>(); var allVertices = new List <CurveVertex>(); foreach (var id in allIds) { var points = CurveUtils.GetDistinctVertices(id, transaction); if (!points.Any()) { continue; } var vertices = points.Select(it => new CurveVertex(it, id)); curveVertices[id] = vertices.ToArray(); allVertices.AddRange(vertices); } kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); }
IEnumerable <ObjectId> GetNearPolygonIds(CurveVertexKdTree <CurveVertex> kdTree, ObjectId polygonId, HashSet <ObjectId> visitedIds, Transaction transaction) { var result = new HashSet <ObjectId>(); var curve = (Curve)transaction.GetObject(polygonId, OpenMode.ForRead); var extents = curve.GeometricExtents; var dir = (extents.MaxPoint - extents.MinPoint).GetNormal(); // 向外扩张0.1 var minPoint = extents.MinPoint - dir * 0.1; var maxPoint = extents.MaxPoint + dir * 0.1; var nearVertices = kdTree.BoxedRange(minPoint.ToArray(), maxPoint.ToArray()); foreach (var curveVertex in nearVertices) { // 不要包含本身 if (curveVertex.Id == polygonId || visitedIds.Contains(curveVertex.Id)) { continue; } result.Add(curveVertex.Id); } return(result); }
public static Dictionary <ObjectId, List <Point3d> > GetCrotchPoints(Database database, IEnumerable <ObjectId> parcelIds) { var result = new Dictionary <ObjectId, List <Point3d> >(); // Create a kd tree. var allVertices = new List <CurveVertex>(); using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var objId in parcelIds) { var curve = transaction.GetObject(objId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } var vertices = CurveUtils.GetDistinctVertices(curve, transaction); allVertices.AddRange(vertices.Select(it => new CurveVertex(it, objId))); } transaction.Commit(); } var kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); // 搜索三岔口 //using (var tolerance = new ToleranceOverrule(null)) using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var parcelId in parcelIds) { var curve = transaction.GetObject(parcelId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } var ptLink = LinkedPoint.GetLinkedPoints(curve, transaction, isLoop: true); var ptTraverse = ptLink; // Use records to improve performance. var records = new Dictionary <LinkedPoint, IEnumerable <CurveVertex> >(); while (ptTraverse != null) { var prev = ptTraverse.Prev; var next = ptTraverse.Next; if (!records.ContainsKey(prev)) { records[prev] = kdTree.NearestNeighbours(prev.Point.ToArray(), radius: 0.001); } if (!records.ContainsKey(ptTraverse)) { records[ptTraverse] = kdTree.NearestNeighbours(ptTraverse.Point.ToArray(), radius: 0.001); } if (!records.ContainsKey(next)) { records[next] = kdTree.NearestNeighbours(next.Point.ToArray(), radius: 0.001); } foreach (var vertex in records[ptTraverse]) { if (result.ContainsKey(parcelId) && result[parcelId].Contains(vertex.Point)) { continue; } if (vertex.Id == parcelId || vertex.Point != ptTraverse.Point) { continue; } var prevVertex = new CurveVertex(prev.Point, vertex.Id); var nextVertex = new CurveVertex(next.Point, vertex.Id); if (records[prev].Contains(prevVertex) && records[next].Contains(nextVertex)) { continue; } List <Point3d> list = null; if (result.ContainsKey(parcelId)) { list = result[parcelId]; } else { list = new List <Point3d>(); result[parcelId] = list; } list.Add(ptTraverse.Point); } ptTraverse = ptTraverse.Next; if (ptTraverse == ptLink) { break; } } } transaction.Commit(); } return(result); }
private bool CheckDangling(CurveVertex vertex, IEnumerable <ObjectId> allIds, HashSet <ObjectId> visitedIds, Stack <CurveVertex> candidates, Dictionary <ObjectId, CurveVertex[]> curveVertices, CurveVertexKdTree <CurveVertex> kdTree) { bool isDangling = true; // Get entities which vertex is on. var neighbors = kdTree.NearestNeighbours(vertex.Point.ToArray(), radius: 0.1); var adjacentIds = neighbors.Select(it => it.Id); foreach (ObjectId adjacentId in adjacentIds) { if (adjacentId == vertex.Id) { continue; } // Check adjacent vertices if (!curveVertices.ContainsKey(adjacentId)) { continue; } var vertices = curveVertices[adjacentId]; foreach (var adjVertex in vertices) { // If it connect to vertex, isDangling is false. if (adjVertex.Point == vertex.Point) { isDangling = false; } else if (!visitedIds.Contains(adjacentId) && (_forDrawing || allIds.Contains(adjacentId))) { candidates.Push(adjVertex); } } // Mark it as visited. visitedIds.Add(adjacentId); } return(isDangling); }
public override void Check(IEnumerable <ObjectId> selectedObjectIds) { if (!selectedObjectIds.Any()) { return; } var allVertices = new List <CurveVertex>(); var curveIds = new List <ObjectId>(); using (var transaction = this.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; } curveIds.Add(objId); var vertices = CurveUtils.GetDistinctVertices(curve, transaction); allVertices.AddRange(vertices.Select(it => new CurveVertex(it, objId))); } transaction.Commit(); } var kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); // Use kd tree to check include. var analyzed = new HashSet <KeyValuePair <ObjectId, ObjectId> >(); using (var transaction = this.Database.TransactionManager.StartTransaction()) { foreach (var objectId in curveIds) { var curve = transaction.GetObject(objectId, OpenMode.ForRead) as Curve; var extents = curve.GeometricExtents; var nearVertices = kdTree.BoxedRange(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray()); foreach (var curveVertex in nearVertices) { if (curveVertex.Id == objectId || analyzed.Contains(new KeyValuePair <ObjectId, ObjectId>(objectId, curveVertex.Id))) { continue; } analyzed.Add(new KeyValuePair <ObjectId, ObjectId>(objectId, curveVertex.Id)); var targetCurve = transaction.GetObject(curveVertex.Id, OpenMode.ForRead) as Curve; if (IsInclude(curve, targetCurve, transaction)) { _includePolygons.Add(new KeyValuePair <ObjectId, ObjectId>(objectId, curveVertex.Id)); } } } transaction.Commit(); } }
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); }
/// <summary> /// 检查和sourceIds相交的objectIds /// </summary> /// <param name="objectIds"></param> /// <param name="sourceIds"></param> public void Check(IEnumerable <ObjectId> objectIds, IEnumerable <ObjectId> sourceIds) { if (!objectIds.Any() || !sourceIds.Any()) { return; } var database = Editor.Document.Database; // Build a kd tree for searching intersection var allVertices = new List <CurveVertex>(); var closedSourceIds = new List <ObjectId>(); using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var objectId in objectIds) { var curve = transaction.GetObject(objectId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } if (!IsCurveClosed(curve)) { continue; } var vertices = CurveUtils.GetDistinctVertices(curve, transaction); allVertices.AddRange(vertices.Select(it => new CurveVertex(it, objectId))); curve.Dispose(); } foreach (var sourceId in sourceIds) { var curve = transaction.GetObject(sourceId, OpenMode.ForRead) as Curve; if (curve == null) { continue; } if (!IsCurveClosed(curve)) { continue; } closedSourceIds.Add(sourceId); curve.Dispose(); } transaction.Commit(); } // Create a kdTree var kdTree = new CurveVertexKdTree <CurveVertex>(allVertices, it => it.Point.ToArray(), ignoreZ: true); // Use kd tree to check intersect. var intersects = new List <PolygonIntersect>(); var analyzed = new HashSet <KeyValuePair <ObjectId, ObjectId> >(); using (var transaction = database.TransactionManager.StartTransaction()) { foreach (var objectId in closedSourceIds) { var curve = transaction.GetObject(objectId, OpenMode.ForRead) as Curve; var extents = curve.GeometricExtents; var nearVertices = kdTree.BoxedRange(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray()); foreach (var curveVertex in nearVertices) { if (curveVertex.Id == objectId || analyzed.Contains(new KeyValuePair <ObjectId, ObjectId>(objectId, curveVertex.Id))) { continue; } analyzed.Add(new KeyValuePair <ObjectId, ObjectId>(objectId, curveVertex.Id)); var polygonIntersect = AnalyzePolygonIntersection(objectId, curveVertex.Id, transaction); if (polygonIntersect != null) { var sourceId = polygonIntersect.Value.SourceId; var targetId = polygonIntersect.Value.TargetId; var existing = intersects.FirstOrDefault(it => it.SourceId == sourceId && it.TargetId == targetId || it.SourceId == targetId && it.TargetId == sourceId); if (existing.Equals(default(PolygonIntersect))) { intersects.Add(polygonIntersect.Value); } } } } transaction.Commit(); } _intersects = intersects; }
private IEnumerable <SEdge <CurveVertex> > VisitCurve(CurveVertex?sourceVertex, ObjectId id, IEnumerable <ObjectId> allIds, HashSet <ObjectId> visitedIds, Stack <KeyValuePair <ObjectId, CurveVertex> > candidates, Dictionary <ObjectId, CurveVertex[]> curveVertices, CurveVertexKdTree <CurveVertex> kdTree, Transaction transaction) { // No need to handle it. if (!curveVertices.ContainsKey(id)) { visitedIds.Add(id); return(new SEdge <CurveVertex> [0]); } var originVertices = curveVertices[id]; var points = originVertices.Select(it => it.Point).ToArray(); // If none of the curve's end points is equal to the point, just return. // It means this curve is not a qualified one because it's not connected to sourceVertex. // Then it will be handled later because it belongs to another loop. if (sourceVertex != null && points.Length > 0 && !points.Contains(sourceVertex.Value.Point)) { bool contains = false; foreach (var point in points) { if (point.IsEqualTo(sourceVertex.Value.Point)) { contains = true; } } if (!contains) { return(new SEdge <CurveVertex> [0]); } } // Mark it as visited. visitedIds.Add(id); // If there is no end points on the entity, just return. if (originVertices.Length <= 0) { return(new SEdge <CurveVertex> [0]); } // Remove the duplicate point // Note: if a curve has 2 same end points, means its a self-loop. var distinctVertices = new List <CurveVertex>(); CurveVertex current = originVertices[0]; distinctVertices.Add(current); for (int i = 1; i < originVertices.Length; i++) { if (originVertices[i] != current) { current = originVertices[i]; distinctVertices.Add(current); } } var result = new List <SEdge <CurveVertex> >(); // Push vertex and adjacent curve into candidates foreach (var vertex in distinctVertices) { if (sourceVertex != null && sourceVertex.Value.Point.IsEqualTo(vertex.Point)) { continue; } var adjacentVertices = kdTree.NearestNeighbours(vertex.Point.ToArray(), radius: 0.1); var adjacentIds = adjacentVertices.Select(it => it.Id); foreach (ObjectId adjacentId in adjacentIds) { // If it has been visited. if (visitedIds.Contains(adjacentId)) { var originVertex = new CurveVertex(vertex.Point, adjacentId); // If this curve has been pushed into the candidates stack before, there must exist a loop. // So we create a back edge to the original vertex. // NOTE: Use candidates.Contains(new KeyValuePair<ObjectId, CurveVertex>(id, originVertex)) // will cause a problem if two point are very close to each other // such as (10.5987284839403,10.2186528623464,0) and (10.5987284839408,10.2186528623464,0) var existing = candidates.FirstOrDefault(it => it.Key == id && it.Value == originVertex); if (!existing.Equals(default(KeyValuePair <ObjectId, CurveVertex>))) { // Create edge back to the old vertex. result.Add(new SEdge <CurveVertex>(vertex, existing.Value)); } //if (candidates.Contains(new KeyValuePair<ObjectId, CurveVertex>(id, originVertex))) //{ // // Create edge back to the old vertex. // result.Add(new SEdge<CurveVertex>(vertex, originVertex)); //} continue; } // If it's not in the collection of selected ids. if (!allIds.Contains(adjacentId)) { continue; } candidates.Push(new KeyValuePair <ObjectId, CurveVertex>(adjacentId, vertex)); } } // Create edges int start = 0; if (sourceVertex != null) { for (int i = 0; i < distinctVertices.Count; i++) { if (distinctVertices[i].Point.IsEqualTo(sourceVertex.Value.Point)) { start = i; // Add edge from sourceVertex to nearest point. result.Add(new SEdge <CurveVertex>(sourceVertex.Value, distinctVertices[start])); break; } } } if (distinctVertices.Count == 1) { // Allan 2015/05/06: Self loop won't be handled - to improve performance. // Self loop, create dummy vertex to let it to be a real loop if (_includeSelfLoop) { var dummy = new CurveVertex(distinctVertices[0].Point + new Vector3d(1, 1, 0), id); result.Add(new SEdge <CurveVertex>(distinctVertices[0], dummy)); result.Add(new SEdge <CurveVertex>(dummy, distinctVertices[0])); } } else { // Must start from the vertex whose poitn is equal to source vertex's point. // Up var previousVertex = distinctVertices[start]; for (int i = start + 1; i < distinctVertices.Count; i++) { // Create a middle point to fix a bug - to avoid a line's two vertices are both in loop, // but actually the line is not in a loop, for example // /\ /\ // / \ / \ // /____\A_______B/____\ // Point A and point B are both in a loop, but line AB is not in a loop. // If I add a dummy point C in the middle of AB, then our graph could easily // to determine C is not in a loop. var middlePoint = previousVertex.Point + (distinctVertices[i].Point - previousVertex.Point) / 2.0; var middleVertex = new CurveVertex(middlePoint, id); result.Add(new SEdge <CurveVertex>(previousVertex, middleVertex)); result.Add(new SEdge <CurveVertex>(middleVertex, distinctVertices[i])); previousVertex = distinctVertices[i]; } // Down previousVertex = distinctVertices[start]; for (int i = start - 1; i >= 0; i--) { var middlePoint = previousVertex.Point + (distinctVertices[i].Point - previousVertex.Point) / 2.0; var middleVertex = new CurveVertex(middlePoint, id); result.Add(new SEdge <CurveVertex>(previousVertex, middleVertex)); result.Add(new SEdge <CurveVertex>(middleVertex, distinctVertices[i])); previousVertex = distinctVertices[i]; } } return(result); }
private IEnumerable <CurveCrossingInfo> SearchDuplicateEntities2(ObjectId curveId, CurveVertexKdTree <CurveVertex> kdTree, HashSet <KeyValuePair <ObjectId, ObjectId> > visited, Transaction transaction) { var result = new List <CurveCrossingInfo>(); var curve = transaction.GetObject(curveId, OpenMode.ForRead) as Curve; if (curve == null) { return(new List <CurveCrossingInfo>()); } var extents = curve.GeometricExtents; var nearVertices = kdTree.BoxedRange(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray()); foreach (var nearVertex in nearVertices) { if (nearVertex.Id == curveId || visited.Contains(new KeyValuePair <ObjectId, ObjectId>(curveId, nearVertex.Id)) || visited.Contains(new KeyValuePair <ObjectId, ObjectId>(nearVertex.Id, curveId))) { continue; } var sourceVertices = CurveUtils.GetDistinctVertices(curve, transaction); var targetVertices = CurveUtils.GetDistinctVertices(nearVertex.Id, transaction); var identical = PolygonIncludeSearcher.AreIdenticalCoordinates(sourceVertices, targetVertices); if (identical) { result.Add(new CurveCrossingInfo(curveId, nearVertex.Id, sourceVertices.ToArray())); } visited.Add(new KeyValuePair <ObjectId, ObjectId>(curveId, nearVertex.Id)); } return(result); }
private IEnumerable <CurveCrossingInfo> SearchDuplicateInfo(KeyValuePair <ObjectId, CurveVertex[]> curveInfo, CurveVertexKdTree <CurveVertex> kdTree, Dictionary <ObjectId, CurveVertex[]> curveInfos, List <Tuple <ObjectId, ObjectId> > visited) { List <CurveCrossingInfo> crossingInfos = new List <CurveCrossingInfo>(); HashSet <ObjectId> candidates = null; Dictionary <ObjectId, List <Point3d> > candidatePoints = new Dictionary <ObjectId, List <Point3d> >(); foreach (var vertex in curveInfo.Value) { var neighbours = kdTree.NearestNeighbours(vertex.Point.ToArray(), _tolerance); neighbours = neighbours.Except(new CurveVertex[] { vertex }); // If there is no neighbour vertex, just return. if (!neighbours.Any()) { if (candidates != null) { candidates = null; } break; } if (candidates == null) { candidates = new HashSet <ObjectId>(neighbours.Select(it => it.Id)); foreach (var id in candidates) { var points = neighbours.Where(it => it.Id == id) .Select(it => it.Point); candidatePoints[id] = new List <Point3d>(points); } } else { candidates.IntersectWith(neighbours.Select(it => it.Id)); if (candidates.Count <= 0) { break; } foreach (var id in candidates) { var points = candidatePoints[id]; var newPoints = neighbours .Where(it => it.Id == id) .Select(it => it.Point); foreach (var newPoint in newPoints) { if (!points.Contains(newPoint)) { points.Add(newPoint); } } } } } if (candidates != null && candidates.Count > 0) { foreach (var candidate in candidates) { // If self, just continue. if (candidate == curveInfo.Key) { continue; } var existing = visited.FirstOrDefault(it => (it.Item1 == curveInfo.Key && it.Item2 == candidate) || (it.Item1 == candidate && it.Item2 == curveInfo.Key)); if (existing != null) { continue; } visited.Add(new Tuple <ObjectId, ObjectId>(curveInfo.Key, candidate)); // Check whether they have same number of vertices. if (curveInfos[candidate].Length != candidatePoints[candidate].Count) { continue; } var points = curveInfo.Value.Select(it => it.Point).ToArray(); var crossingInfo = new CurveCrossingInfo(curveInfo.Key, candidate, points); crossingInfos.Add(crossingInfo); } } return(crossingInfos); }
private void SearchDuplicateEntities(Dictionary <ObjectId, CurveVertex[]> curveInfos, CurveVertexKdTree <CurveVertex> kdTree) { var crossingInfos = new List <CurveCrossingInfo>(); List <Tuple <ObjectId, ObjectId> > visited = new List <Tuple <ObjectId, ObjectId> >(); foreach (var curveInfo in curveInfos) { var infos = SearchDuplicateInfo(curveInfo, kdTree, curveInfos, visited); if (infos.Any()) { crossingInfos.AddRange(infos); } } _crossingInfos = crossingInfos; }