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);
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        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);
                    }
                }
        }
Beispiel #5
0
        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;
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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();
            }
        }
Beispiel #17
0
        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;
        }
Beispiel #19
0
        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;
        }