예제 #1
0
        public IEnumerable <CutSubcurve> ConnectedSubcurvesFromLeftToRight(
            CutSubcurve startCurve)
        {
            _connectedSubcurves.Sort(new CutSubcurveComparer(startCurve, this, false));

            return(_connectedSubcurves);
        }
예제 #2
0
        public bool TryJoinNonForkingNeighbourCandidates(
            [NotNull] CutSubcurve subcurve,
            [NotNull] List <CutSubcurve> replacedSubcurves,
            out CutSubcurve result)
        {
            if (!subcurve.IsReshapeMemberCandidate ||
                subcurve.IsFiltered)
            {
                result = null;
                return(false);
            }

            result = subcurve;

            if (!result.TouchAtFromPoint)
            {
                TryMergeWithSingleAdjacentCandidate(ref result, subcurve.FromNode,
                                                    replacedSubcurves);
            }

            if (!result.TouchAtToPoint)
            {
                TryMergeWithSingleAdjacentCandidate(ref result, subcurve.ToNode,
                                                    replacedSubcurves);
            }

            return(result != subcurve);
        }
예제 #3
0
        private static bool FullyWithinAnyExtent(IPolyline highLevelPath,
                                                 CutSubcurve cutSubcurve,
                                                 IEnumerable <IEnvelope> extents)
        {
            foreach (IEnvelope extent in extents)
            {
                if (extent.IsEmpty)
                {
                    continue;
                }

                if (GeometryUtils.Contains(extent, highLevelPath))
                {
                    if (!cutSubcurve.CanReshape &&
                        (GeometryUtils.Touches(extent, highLevelPath.FromPoint) ||
                         GeometryUtils.Touches(extent, highLevelPath.ToPoint)))
                    {
                        // it was cut off by the extent
                        continue;
                    }

                    return(true);
                }
            }

            return(false);
        }
예제 #4
0
        private static SubcurveNode GetNodeAt(IPoint checkPoint, CutSubcurve cutSubcurve1,
                                              CutSubcurve cutSubcurve2,
                                              out bool isTouchingSource)
        {
            SubcurveNode result;

            if (GeometryUtils.AreEqualInXY(checkPoint, cutSubcurve1.Path.FromPoint))
            {
                result           = cutSubcurve1.FromNode;
                isTouchingSource = cutSubcurve1.TouchAtFromPoint;
            }
            else if (GeometryUtils.AreEqualInXY(checkPoint, cutSubcurve1.Path.ToPoint))
            {
                result           = cutSubcurve1.ToNode;
                isTouchingSource = cutSubcurve1.TouchAtToPoint;
            }
            else if (GeometryUtils.AreEqualInXY(checkPoint, cutSubcurve2.Path.FromPoint))
            {
                result           = cutSubcurve2.FromNode;
                isTouchingSource = cutSubcurve2.TouchAtFromPoint;
            }
            else
            {
                Assert.True(
                    GeometryUtils.AreEqualInXY(checkPoint, cutSubcurve2.Path.ToPoint),
                    "Unexpected situation after merging adjacent subcurves.");

                result           = cutSubcurve2.ToNode;
                isTouchingSource = cutSubcurve2.TouchAtToPoint;
            }

            return(result);
        }
예제 #5
0
        private static bool IsConnected(CutSubcurve subcurve, SubcurveNode atNode,
                                        ICollection <SubcurveNode> checkedNodes,
                                        ICollection <CutSubcurve> intermediateCurves,
                                        Predicate <CutSubcurve> connectCondition)
        {
            // TODO: cache the thisSubcurve on the subcurve to improve performance
            if (_msg.IsVerboseDebugEnabled)
            {
                _msg.DebugFormat("Checking if connected at {0}/{1}", atNode.X, atNode.Y);
            }

            if (connectCondition != null && !connectCondition(subcurve))
            {
                return(false);
            }

            if ((atNode == subcurve.FromNode && subcurve.TouchAtFromPoint) ||
                (atNode == subcurve.ToNode && subcurve.TouchAtToPoint))
            {
                checkedNodes.Add(atNode);
                intermediateCurves.Add(subcurve);

                return(true);
            }

            if (checkedNodes.Contains(atNode))
            {
                return(false);
            }

            // block the node to avoid circles
            checkedNodes.Add(atNode);

            // NOTE: sometimes reshape candidates are not found because the node traversal cuts off the other
            //	     node's path (and vice versa when the second starts first):
            // TODO: always try the left-most / or for the other node the right-most subcurve (invert in second run)
            //       to avoid cutting the other node's path -> this is not the perfect solution either (debug)
            // TODO: minimal but robust solution: make sure both ends are connected regardless of the other's path (only exclude other node)

            //IEnumerable<CutSubcurve> leaves = traverseRightCurvesFirst
            //                                    ? atNode.ConnectedSubcurvesFromRightToLeft(subcurve)
            //                                    : atNode.ConnectedSubcurvesFromLeftToRight(subcurve);

            foreach (CutSubcurve connectedSubcurve in atNode.ConnectedSubcurves)
            {
                if (connectedSubcurve != subcurve &&
                    IsConnected(connectedSubcurve, connectedSubcurve.OtherNode(atNode),
                                checkedNodes,
                                intermediateCurves, connectCondition))
                {
                    intermediateCurves.Add(subcurve);

                    return(true);
                }
            }

            return(false);
        }
예제 #6
0
        public bool IsExcluded(CutSubcurve cutSubcurve)
        {
            var highLevelPath =
                (IPolyline)GeometryUtils.GetHighLevelGeometry(cutSubcurve.Path, true);

            if (_currentlyVisibleExtents != null)
            {
                if (!FullyWithinAnyExtent(highLevelPath, cutSubcurve,
                                          _currentlyVisibleExtents))
                {
                    return(true);
                }
            }

            if (_filterOptions.ExcludeOutsideSource)
            {
                var mustInteriorIntersectPoly = _currentSourceGeometry as IPolygon;

                if (mustInteriorIntersectPoly != null &&
                    !GeometryUtils.InteriorIntersects(
                        mustInteriorIntersectPoly, highLevelPath))
                {
                    return(true);
                }
            }

            if (_mustBeWithinSourceBuffer != null)
            {
                if (!GeometryUtils.Contains(_mustBeWithinSourceBuffer, highLevelPath))
                {
                    return(true);
                }
            }

            if (_filterOptions.ExcludeResultingInOverlaps &&
                _targetUnionPoly != null && _sourceTargetPolyUnionBoundary != null)
            {
                // Avoid Error in Disjoint/Contains: Spatial References of provided geometries are not consistent.
                // This happens sometimes, probably due to map SR different to data SR.
                // But also with minimum tolerance: the subcurves are calculated in minimum tolerance
                GeometryUtils.EnsureSpatialReference(_targetUnionPoly,
                                                     highLevelPath.SpatialReference);

                GeometryUtils.EnsureSpatialReference(_sourceTargetPolyUnionBoundary,
                                                     highLevelPath.SpatialReference);

                if (ResultsInOverlaps(highLevelPath, _targetUnionPoly,
                                      _sourceTargetPolyUnionBoundary))
                {
                    return(true);
                }
            }

            Marshal.ReleaseComObject(highLevelPath);

            return(false);
        }
예제 #7
0
        private static void TryMergeWithSingleAdjacentCandidate(
            ref CutSubcurve thisSubcurve, SubcurveNode inNode,
            List <CutSubcurve> replacedSubcurves)
        {
            CutSubcurve singleConnectedCandidataCurve = null;

            foreach (CutSubcurve adjacentSubcurve in inNode.ConnectedSubcurves)
            {
                if (adjacentSubcurve == thisSubcurve)
                {
                    continue;
                }

                if (!adjacentSubcurve.IsReshapeMemberCandidate ||
                    adjacentSubcurve.IsFiltered)
                {
                    // already green or red or grey:
                    continue;
                }

                if (replacedSubcurves.Contains(adjacentSubcurve))
                {
                    continue;
                }

                if (TouchesSourceInNode(adjacentSubcurve, inNode))
                {
                    // do not merge across source lines
                    continue;
                }

                if (singleConnectedCandidataCurve == null)
                {
                    singleConnectedCandidataCurve = adjacentSubcurve;
                }
                else
                {
                    // more than one - cannot merge
                    return;
                }
            }

            if (singleConnectedCandidataCurve == null)
            {
                return;
            }

            // Add to replaced curves before assigning the final thisSubcurve through merging the two
            replacedSubcurves.Add(thisSubcurve);
            replacedSubcurves.Add(singleConnectedCandidataCurve);

            thisSubcurve = Replace(thisSubcurve, singleConnectedCandidataCurve, inNode);
        }
예제 #8
0
        private static bool TouchesSourceInNode(CutSubcurve subcurve, SubcurveNode inNode)
        {
            if (subcurve.FromNode.Equals(inNode))
            {
                return(subcurve.TouchAtFromPoint);
            }

            if (subcurve.ToNode.Equals(inNode))
            {
                return(subcurve.TouchAtToPoint);
            }

            // Assert.CantReach() here?
            return(false);
        }
예제 #9
0
        private static void JoinNonForkingSubcurves(
            ICollection <CutSubcurve> inSubcurveCollection)
        {
            var removedCurves    = new List <CutSubcurve>();
            var additionalCurves = new List <CutSubcurve>();

            foreach (CutSubcurve reshapeSubcurve in inSubcurveCollection)
            {
                if (removedCurves.Contains(reshapeSubcurve))
                {
                    continue;
                }

                if (reshapeSubcurve.IsReshapeMemberCandidate)
                {
                    // try building up a non-forking path from the non-touching end through a
                    // set of connected subcurves back to the geometry to reshape
                    CutSubcurve currentInputCurve = reshapeSubcurve;
                    CutSubcurve mergedCurve;

                    while (reshapeSubcurve.TryJoinNonForkingNeighbourCandidates(
                               currentInputCurve, removedCurves, out mergedCurve))
                    {
                        currentInputCurve = mergedCurve;
                    }

                    if (currentInputCurve != reshapeSubcurve)
                    {
                        // one or more merges happened:
                        additionalCurves.Add(currentInputCurve);
                    }
                }
            }

            foreach (CutSubcurve removedCurve in removedCurves)
            {
                inSubcurveCollection.Remove(removedCurve);
            }

            foreach (CutSubcurve additionalCurve in additionalCurves)
            {
                inSubcurveCollection.Add(additionalCurve);
            }
        }
예제 #10
0
        private bool Equals(CutSubcurve other)
        {
            if (ReferenceEquals(null, other))
            {
                return(false);
            }

            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            return
                (Equals(other.Source, Source) &&
                 other._touchAtFromPoint.Equals(_touchAtFromPoint) &&
                 other._touchAtToPoint.Equals(_touchAtToPoint) &&
                 (_path.Equals(other._path) ||                    // path can be reference equal
                  ((IClone)_path).IsEqual((IClone)other._path))); // or IClone.IsEqual
        }
예제 #11
0
        private bool ApplyReshapePath(IGeometry geometryToReshape, IPath reshapePath,
                                      NotificationCollection notifications,
                                      [CanBeNull] CutSubcurve cutSubcurve,
                                      IDictionary <IGeometry, NotificationCollection>
                                      reshapedGeometries)
        {
            var reshapeInfo =
                new ReshapeInfo(geometryToReshape, reshapePath,
                                notifications)
            {
                PartIndexToReshape = 0,                         // TODO
                CutReshapePath     = cutSubcurve
            };

            // TODO: make ReshapeSingleGeometryInUnion not depend on unionReshapeInfo and use the same general workflow?

            bool reshaped = ReshapeSinglePolygonInUnion(reshapeInfo);

            if (reshaped)
            {
                // to avoid incorrect relational operator results in for the next path on target
                ((ISegmentCollection)geometryToReshape).SegmentsChanged();

                AddToRefreshArea(reshapeInfo);
            }

            // move adding notfications to caller?
            if (reshaped && !reshapedGeometries.ContainsKey(reshapeInfo.GeometryToReshape))
            {
                reshapedGeometries.Add(reshapeInfo.GeometryToReshape, reshapeInfo.Notifications);
            }
            else
            {
                if (reshapeInfo.Notifications != null)
                {
                    NotificationUtils.Add(notifications,
                                          reshapeInfo.Notifications.Concatenate(" "));
                }
            }

            return(reshaped);
        }
예제 #12
0
        private static double GetLineAngle([NotNull] CutSubcurve subcurve,
                                           SubcurveNode atNode)
        {
            var segments = (ISegmentCollection)subcurve.Path;

            ISegment segment;

            var reverseOrientation = false;

            if (atNode == subcurve.ToNode)
            {
                // use last segment and the line needs to be inverted
                segment = segments.Segment[segments.SegmentCount - 1];

                reverseOrientation = true;
            }
            else
            {
                segment = segments.Segment[0];
            }

            var line = segment as ILine;

            if (line == null)
            {
                line = new LineClass();
                segment.QueryTangent(esriSegmentExtension.esriNoExtension, 1, true, 10,
                                     line);
            }

            double angle = line.Angle;

            if (reverseOrientation)
            {
                angle = angle >= Math.PI
                                                ? angle - Math.PI
                                                : angle + Math.PI;
            }

            return(angle);
        }
예제 #13
0
        private static CutSubcurve CreateCutSubcurve(
            [NotNull] IPath path,
            [CanBeNull] IPointCollection intersectionPoints,
            [NotNull] IDictionary <SubcurveNode, SubcurveNode> allNodes,
            bool?touchingDifferentParts,
            IPolyline targetPolyline,
            double stitchPointSearchTol)
        {
            var touchAtFromPoint = false;
            var touchAtToPoint   = false;

            if (intersectionPoints != null)
            {
                touchAtFromPoint = GeometryUtils.Intersects(
                    path.FromPoint, (IGeometry)intersectionPoints);

                touchAtToPoint = GeometryUtils.Intersects(
                    path.ToPoint, (IGeometry)intersectionPoints);
            }

            var fromNode = new SubcurveNode(path.FromPoint.X, path.FromPoint.Y);

            if (allNodes.ContainsKey(fromNode))
            {
                fromNode = allNodes[fromNode];
            }
            else
            {
                allNodes.Add(fromNode, fromNode);
            }

            var toNode = new SubcurveNode(path.ToPoint.X, path.ToPoint.Y);

            if (allNodes.ContainsKey(toNode))
            {
                toNode = allNodes[toNode];
            }
            else
            {
                allNodes.Add(toNode, toNode);
            }

            var cutSubcurve = new CutSubcurve(path, touchAtFromPoint, touchAtToPoint,
                                              fromNode, toNode, touchingDifferentParts);

            // Identify stitch points, i.e. points that do not exist in the target and should not end up in the
            // reshaped geometry if several adjacent cutsubcurves are applied together.
            if (touchAtFromPoint)
            {
                IPoint point = cutSubcurve.Path.FromPoint;

                ISegment targetSegment;
                cutSubcurve.FromPointIsStitchPoint = IsNoTargetVertex(
                    point, targetPolyline, stitchPointSearchTol, out targetSegment);

                cutSubcurve.TargetSegmentAtFromPoint = targetSegment;
            }

            if (touchAtToPoint)
            {
                IPoint point = cutSubcurve.Path.ToPoint;

                ISegment targetSegment;
                cutSubcurve.ToPointIsStitchPoint = IsNoTargetVertex(
                    point, targetPolyline, stitchPointSearchTol, out targetSegment);

                cutSubcurve.TargetSegmentAtToPoint = targetSegment;
            }

            fromNode.ConnectedSubcurves.Add(cutSubcurve);
            toNode.ConnectedSubcurves.Add(cutSubcurve);

            return(cutSubcurve);
        }
예제 #14
0
        private static CutSubcurve Replace(CutSubcurve cutSubcurve1,
                                           CutSubcurve cutSubcurve2,
                                           SubcurveNode mergeNode)
        {
            IGeometryCollection mergedCollection =
                ReshapeUtils.GetSimplifiedReshapeCurves(
                    new List <CutSubcurve> {
                cutSubcurve1, cutSubcurve2
            });

            Assert.AreEqual(1, mergedCollection.GeometryCount,
                            "Unexpected number of geometries after merging adjacent subcurves");

            var newPath = (IPath)mergedCollection.get_Geometry(0);

            bool         touchAtFrom;
            SubcurveNode oldNodeAtFrom = GetNodeAt(newPath.FromPoint, cutSubcurve1,
                                                   cutSubcurve2,
                                                   out touchAtFrom);

            bool         touchAtTo;
            SubcurveNode oldNodeAtTo = GetNodeAt(newPath.ToPoint, cutSubcurve1,
                                                 cutSubcurve2,
                                                 out touchAtTo);

            if (oldNodeAtFrom.ConnectedSubcurves.Contains(cutSubcurve1))
            {
                oldNodeAtFrom.ConnectedSubcurves.Remove(cutSubcurve1);
            }

            if (oldNodeAtFrom.ConnectedSubcurves.Contains(cutSubcurve2))
            {
                oldNodeAtFrom.ConnectedSubcurves.Remove(cutSubcurve2);
            }

            if (oldNodeAtTo.ConnectedSubcurves.Contains(cutSubcurve1))
            {
                oldNodeAtTo.ConnectedSubcurves.Remove(cutSubcurve1);
            }

            if (oldNodeAtTo.ConnectedSubcurves.Contains(cutSubcurve2))
            {
                oldNodeAtTo.ConnectedSubcurves.Remove(cutSubcurve2);
            }

            var result = new CutSubcurve(newPath, touchAtFrom, touchAtTo, oldNodeAtFrom,
                                         oldNodeAtTo);

            result.Source = cutSubcurve1.Source;

            oldNodeAtFrom.ConnectedSubcurves.Add(result);
            oldNodeAtTo.ConnectedSubcurves.Add(result);

            // Old target intersection points: Add them if they were not stitch points removed after simplify:
            IPoint connectPoint = GeometryFactory.CreatePoint(mergeNode.X, mergeNode.Y,
                                                              newPath.SpatialReference);

            int partIdx;
            int?connectIndex = GeometryUtils.FindHitVertexIndex(
                newPath, connectPoint, GeometryUtils.GetXyTolerance(newPath),
                out partIdx);

            if (connectIndex != null)
            {
                result.AddExtraPotentialTargetInsertPoint(
                    ((IPointCollection)newPath).get_Point((int)connectIndex));
            }

            return(result);
        }