/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="ISegmentString" />s being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) { return; } Coordinate[] coordinates0 = e0.Coordinates; Coordinate p00 = coordinates0[segIndex0]; Coordinate p01 = coordinates0[segIndex0 + 1]; Coordinate[] coordinates1 = e1.Coordinates; Coordinate p10 = coordinates1[segIndex1]; Coordinate p11 = coordinates1[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) { if (_li.IsInteriorIntersection()) { for (int intIndex = 0; intIndex < _li.IntersectionNum; intIndex++) { _interiorIntersections.Add(_li.GetIntersection(intIndex)); } ((NodedSegmentString)e0).AddIntersections(_li, segIndex0, 0); ((NodedSegmentString)e1).AddIntersections(_li, segIndex1, 1); } } }
/// <summary> /// Test if two segments are adjacent segments on the same SegmentString. /// Note that closed edges require a special check for the point shared by the beginning /// and end segments. /// </summary> private static bool IsAdjacent(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 != e1) { return(false); } bool isAdjacent = Math.Abs(segIndex0 - segIndex1) == 1; if (isAdjacent) { return(true); } if (e0.IsClosed) { int maxSegIndex = e0.Count - 1; if ((segIndex0 == 0 && segIndex1 == maxSegIndex) || (segIndex1 == 0 && segIndex0 == maxSegIndex)) { return(true); } } return(false); }
/// <summary> /// If an endpoint of one segment is near /// the <i>interior</i> of the other segment, add it as an intersection. /// EXCEPT if the endpoint is also close to a segment endpoint /// (since this can introduce "zigs" in the linework). /// <para/> /// This resolves situations where /// a segment A endpoint is extremely close to another segment B, /// but is not quite crossing. Due to robustness issues /// in orientation detection, this can /// result in the snapped segment A crossing segment B /// without a node being introduced. /// </summary> private void ProcessNearVertex(ISegmentString srcSS, int srcIndex, Coordinate p, ISegmentString ss, int segIndex, Coordinate p0, Coordinate p1) { /* * Don't add intersection if candidate vertex is near endpoints of segment. * This avoids creating "zig-zag" linework * (since the vertex could actually be outside the segment envelope). * Also, this should have already been snapped. */ if (p.Distance(p0) < _snapTolerance) { return; } if (p.Distance(p1) < _snapTolerance) { return; } double distSeg = DistanceComputer.PointToSegment(p, p0, p1); if (distSeg < _snapTolerance) { // add vertex to target segment ((NodedSegmentString)ss).AddIntersection(p, segIndex); // add node at vertex to source SS ((NodedSegmentString)srcSS).AddIntersection(p, srcIndex); } }
/// <summary> /// Snaps (nodes) all interacting segments to this hot pixel. /// The hot pixel may represent a vertex of an edge, /// in which case this routine uses the optimization /// of not noding the vertex itself /// </summary> /// <param name="hotPixel">The hot pixel to snap to.</param> /// <param name="parentEdge">The edge containing the vertex, if applicable, or <c>null</c>.</param> /// <param name="hotPixelVertexIndex"></param> /// <returns><c>true</c> if a node was added for this pixel.</returns> public bool Snap(HotPixel hotPixel, ISegmentString parentEdge, int hotPixelVertexIndex) { var pixelEnv = hotPixel.GetSafeEnvelope(); var hotPixelSnapAction = new HotPixelSnapAction(hotPixel, parentEdge, hotPixelVertexIndex); _index.Query(pixelEnv, new QueryVisitor(pixelEnv, hotPixelSnapAction)); return(hotPixelSnapAction.IsNodeAdded); }
private void CheckInteriorIntersections(ISegmentString ss0, ISegmentString ss1) { var pts0 = ss0.Coordinates; var pts1 = ss1.Coordinates; for (var i0 = 0; i0 < pts0.Length - 1; i0++) for (var i1 = 0; i1 < pts1.Length - 1; i1++) CheckInteriorIntersections(ss0, i0, ss1, i1); }
private static void AddToMonoChains(ISegmentString segStr, List<MonotoneChain> monotoneChains) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var mc in segChains) { monotoneChains.Add(mc); } }
private void AddToIndex(ISegmentString segStr) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var mc in segChains) { _index.Insert(mc.Envelope, mc); } }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="e1"></param> private void ComputeIntersects(ISegmentString e0, ISegmentString e1) { Coordinate[] pts0 = e0.Coordinates; Coordinate[] pts1 = e1.Coordinates; for (int i0 = 0; i0 < pts0.Length - 1; i0++) for (int i1 = 0; i1 < pts1.Length - 1; i1++) SegmentIntersector.ProcessIntersections(e0, i0, e1, i1); }
private static void CheckCollapses(ISegmentString ss) { var pts = ss.Coordinates; for (int i = 0; i < pts.Length - 2; i++) { CheckCollapse(pts[i], pts[i + 1], pts[i + 2]); } }
private static void AddToMonoChains(ISegmentString segStr, List <MonotoneChain> monotoneChains) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var mc in segChains) { monotoneChains.Add(mc); } }
private void AddToMonoChains(ISegmentString segStr, List <MonotoneChain> monotoneChains) { IList <MonotoneChain> segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (MonotoneChain mc in segChains) { mc.Id = _processCounter++; monotoneChains.Add(mc); } }
private void AddToIndex(ISegmentString segStr) { IList <MonotoneChain> segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (MonotoneChain mc in segChains) { mc.Id = _indexCounter++; _index.Insert(mc.Envelope, mc); } }
///<summary> /// This method is called by clients of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). ///</summary> ///<param name="e0"></param> ///<param name="segIndex0"></param> ///<param name="e1"></param> ///<param name="segIndex1"></param> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // short-circuit if intersection already found if (!FindAllIntersections && HasIntersection) { return; } // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) { return; } /* * If enabled, only test end segments (on either segString). * */ if (CheckEndSegmentsOnly) { Boolean isEndSegPresent = IsEndSegment(e0, segIndex0) || IsEndSegment(e1, segIndex1); if (!isEndSegPresent) { return; } } Coordinate p00 = e0.Coordinates[segIndex0]; Coordinate p01 = e0.Coordinates[segIndex0 + 1]; Coordinate p10 = e1.Coordinates[segIndex1]; Coordinate p11 = e1.Coordinates[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) { if (_li.IsInteriorIntersection()) { _intSegments = new Coordinate[4]; _intSegments[0] = p00; _intSegments[1] = p01; _intSegments[2] = p10; _intSegments[3] = p11; _interiorIntersection = _li.GetIntersection(0); if (KeepIntersections) { _intersections.Add(_interiorIntersection); } intersectionCount++; } } }
/// <summary> /// /// </summary> /// <param name="segStr"></param> private void Add(ISegmentString segStr) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var mc in segChains) { mc.Id = _idCounter++; _index.Insert(mc.Envelope, mc); _monoChains.Add(mc); } }
private static IGeometry ConvertSegStrings(IEnumerator<ISegmentString> it) { var fact = new GeometryFactory(); var lines = new List<IGeometry>(); while (it.MoveNext()) { ISegmentString ss = it.Current; ILineString line = fact.CreateLineString(ss.Coordinates); lines.Add(line); } return fact.BuildGeometry(lines); }
///<summary> /// Tests whether a segment in a <see cref="ISegmentString" /> is an end segment. /// (either the first or last). ///</summary> ///<param name="segStr">a segment string</param> ///<param name="index">the index of a segment in the segment string</param> ///<returns>true if the segment is an end segment</returns> private static Boolean IsEndSegment(ISegmentString segStr, int index) { if (index == 0) { return(true); } if (index >= segStr.Count - 2) { return(true); } return(false); }
/// <summary> /// /// </summary> /// <param name="segStr"></param> private void Add(ISegmentString segStr) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var mc in segChains) { mc.Id = _idCounter++; //mc.OverlapTolerance = _overlapTolerance; _index.Insert(mc.GetEnvelope(_overlapTolerance), mc); _monoChains.Add(mc); } }
/// <summary> /// Test if the segmentString is a collapsed edge /// of the form ABA. /// These should not be returned by noding. /// </summary> /// <param name="s">A segment string</param> /// <returns><c>true</c> if the segment string is collapsed</returns> private bool IsCollapsed(ISegmentString s) { if (s.Count != 3) { return(false); } bool isEndsEqual = s.Coordinates[0].Equals2D(s.Coordinates[2]); bool isMiddleDifferent = !s.Coordinates[0].Equals2D(s.Coordinates[1]); bool isCollapsed = isEndsEqual && isMiddleDifferent; return(isCollapsed); }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="e1"></param> private void ComputeIntersects(ISegmentString e0, ISegmentString e1) { Coordinate[] pts0 = e0.Coordinates; Coordinate[] pts1 = e1.Coordinates; for (int i0 = 0; i0 < pts0.Length - 1; i0++) { for (int i1 = 0; i1 < pts1.Length - 1; i1++) { SegmentIntersector.ProcessIntersections(e0, i0, e1, i1); } } }
private void CheckInteriorIntersections(ISegmentString ss0, ISegmentString ss1) { var pts0 = ss0.Coordinates; var pts1 = ss1.Coordinates; for (int i0 = 0; i0 < pts0.Length - 1; i0++) { for (int i1 = 0; i1 < pts1.Length - 1; i1++) { CheckInteriorIntersections(ss0, i0, ss1, i1); } } }
///<summary> /// This method is called by clients of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected. ///</summary> /// <remarks> /// Note that some clients (such as <see cref="MonotoneChain"/>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </remarks> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // don't intersect segment with itself if (e0 == e1 && segIndex0 == segIndex1) { return; } NumTests++; ICoordinate p00 = e0.Coordinates[segIndex0]; ICoordinate p01 = e0.Coordinates[segIndex0 + 1]; ICoordinate p10 = e1.Coordinates[segIndex1]; ICoordinate p11 = e1.Coordinates[segIndex1 + 1]; li.ComputeIntersection(p00, p01, p10, p11); //if (li.hasIntersection() && li.isProper()) Debug.println(li); if (li.HasIntersection) { //intersectionFound = true; NumIntersections++; if (li.IsInteriorIntersection()) { NumInteriorIntersections++; _hasInterior = true; //System.out.println(li); } // if the segments are adjacent they have at least one trivial intersection, // the shared endpoint. Don't bother adding it if it is the // only intersection. if (!IsTrivialIntersection(e0, segIndex0, e1, segIndex1)) { _hasIntersection = true; // only add intersection to test geom (the line) ((NodedSegmentString)e1).AddIntersections(li, segIndex1, 1); if (li.IsProper) { NumProperIntersections++; //Debug.println(li.toString()); Debug.println(li.getIntersection(0)); //properIntersectionPoint = (Coordinate) li.getIntersection(0).clone(); _hasProper = true; _hasProperInterior = true; } } } }
/// <summary> /// Processes all of the segment pairs in the given segment strings /// using the given <paramref name="segInt">SegmentIntersector</paramref>. /// </summary> /// <param name="ss0">A segment string</param> /// <param name="ss1">A segment string</param> /// <param name="segInt">The segment intersector to use</param> private static void Intersect(ISegmentString ss0, ISegmentString ss1, ISegmentIntersector segInt) { var pts0 = ss0.Coordinates; var pts1 = ss1.Coordinates; for (var i0 = 0; i0 < pts0.Length - 1; i0++) { for (var i1 = 0; i1 < pts1.Length - 1; i1++) { segInt.ProcessIntersections(ss0, i0, ss1, i1); if (segInt.IsDone) return; } } }
private static void ExtractSegments(ISegmentString ss, List <ISegmentString> segList) { var coords = ss.Coordinates; object context = ss.Context; int cnt = ss.Count; for (int i = 0; i < cnt - 1; i++) { var p0 = coords[i]; var p1 = coords[i + 1]; var seg = new BasicSegmentString(new Coordinate[] { p0, p1 }, context); segList.Add(seg); } }
private void CheckInteriorIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) return; var p00 = e0.Coordinates[segIndex0]; var p01 = e0.Coordinates[segIndex0 + 1]; var p10 = e1.Coordinates[segIndex1]; var p11 = e1.Coordinates[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) if (_li.IsProper || HasInteriorIntersection(_li, p00, p01) || HasInteriorIntersection(_li, p10, p11)) throw new ApplicationException(String.Format( "found non-noded intersection at {0}-{1} and {2}-{3}", p00, p01, p10, p11)); }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected. /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </summary> public void ProcessIntersections( ISegmentString seg0, int segIndex0, ISegmentString seg1, int segIndex1 ) { // don't bother intersecting a segment with itself if (seg0 == seg1 && segIndex0 == segIndex1) { return; } var p00 = seg0.Coordinates[segIndex0]; var p01 = seg0.Coordinates[segIndex0 + 1]; var p10 = seg1.Coordinates[segIndex1]; var p11 = seg1.Coordinates[segIndex1 + 1]; /* * Don't node intersections which are just * due to the shared vertex of adjacent segments. */ if (!IsAdjacent(seg0, segIndex0, seg1, segIndex1)) { _li.ComputeIntersection(p00, p01, p10, p11); //if (_li.HasIntersection && _li.IsProper) System.Diagnostics.Debug.WriteLine(_li); /* * Process single point intersections only. * Two-point (colinear) ones will be handled by the near-vertex code */ if (_li.HasIntersection && _li.IntersectionNum == 1) { var intPt = _li.GetIntersection(0); var snapPt = _snapPointIndex.Snap(intPt); ((NodedSegmentString)seg0).AddIntersection(snapPt, segIndex0); ((NodedSegmentString)seg1).AddIntersection(snapPt, segIndex1); } } /* * The segments must also be snapped to the other segment endpoints. */ ProcessNearVertex(seg0, segIndex0, p00, seg1, segIndex1, p10, p11); ProcessNearVertex(seg0, segIndex0, p01, seg1, segIndex1, p10, p11); ProcessNearVertex(seg1, segIndex1, p10, seg0, segIndex0, p00, p01); ProcessNearVertex(seg1, segIndex1, p11, seg0, segIndex0, p00, p01); }
/// <summary> /// Processes all of the segment pairs in the given segment strings /// using the given <paramref name="segInt">SegmentIntersector</paramref>. /// </summary> /// <param name="ss0">A segment string</param> /// <param name="ss1">A segment string</param> /// <param name="segInt">The segment intersector to use</param> private static void Intersect(ISegmentString ss0, ISegmentString ss1, ISegmentIntersector segInt) { var pts0 = ss0.Coordinates; var pts1 = ss1.Coordinates; for (int i0 = 0; i0 < pts0.Length - 1; i0++) { for (int i1 = 0; i1 < pts1.Length - 1; i1++) { segInt.ProcessIntersections(ss0, i0, ss1, i1); if (segInt.IsDone) { return; } } } }
/// <summary> /// Dissolve the given <see cref="ISegmentString" />. /// </summary> /// <param name="segString"></param> public void Dissolve(ISegmentString segString) { var oca = new OrientedCoordinateArray(segString.Coordinates); var existing = FindMatching(oca /*, segString*/); if (existing == null) { Add(oca, segString); } else { if (_merger != null) { bool isSameOrientation = CoordinateArrays.Equals(existing.Coordinates, segString.Coordinates); _merger.Merge(existing, segString, isSameOrientation); } } }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/> /// s being intersected. /// Note that some clients (such as <c>MonotoneChain</c> s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g.by an disjoint envelope test). /// </summary> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) { return; } var p00 = e0.Coordinates[segIndex0]; var p01 = e0.Coordinates[segIndex0 + 1]; var p10 = e1.Coordinates[segIndex1]; var p11 = e1.Coordinates[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); //if (li.hasIntersection() && li.isProper()) Debug.println(li); if (_li.HasIntersection) { if (_li.IsInteriorIntersection()) { for (int intIndex = 0; intIndex < _li.IntersectionNum; intIndex++) { Intersections.Add(_li.GetIntersection(intIndex)); } ((NodedSegmentString)e0).AddIntersections(_li, segIndex0, 0); ((NodedSegmentString)e1).AddIntersections(_li, segIndex1, 1); return; } } /* * Segments did not actually intersect, within the limits of orientation index robustness. * * To avoid certain robustness issues in snap-rounding, * also treat very near vertex-segment situations as intersections. */ ProcessNearVertex(p00, e1, segIndex1, p10, p11); ProcessNearVertex(p01, e1, segIndex1, p10, p11); ProcessNearVertex(p10, e0, segIndex0, p00, p01); ProcessNearVertex(p11, e0, segIndex0, p00, p01); }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="ISegmentString" /> being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>") may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) { return; } NumTests++; Coordinate[] coordinates0 = e0.Coordinates; Coordinate p00 = coordinates0[segIndex0]; Coordinate p01 = coordinates0[segIndex0 + 1]; Coordinate[] coordinates1 = e1.Coordinates; Coordinate p10 = coordinates1[segIndex1]; Coordinate p11 = coordinates1[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) { NumIntersections++; if (_li.IsInteriorIntersection()) { NumInteriorIntersections++; _hasInterior = true; } // if the segments are adjacent they have at least one trivial intersection, // the shared endpoint. Don't bother adding it if it is the // only intersection. if (!IsTrivialIntersection(e0, segIndex0, e1, segIndex1)) { _hasIntersection = true; ((NodedSegmentString)e0).AddIntersections(_li, segIndex0, 0); ((NodedSegmentString)e1).AddIntersections(_li, segIndex1, 1); if (_li.IsProper) { NumProperIntersections++; _hasProper = true; _hasProperInterior = true; } } } }
private void CheckInteriorIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) { return; } var p00 = e0.Coordinates[segIndex0]; var p01 = e0.Coordinates[segIndex0 + 1]; var p10 = e1.Coordinates[segIndex1]; var p11 = e1.Coordinates[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) { if (_li.IsProper || HasInteriorIntersection(_li, p00, p01) || HasInteriorIntersection(_li, p10, p11)) { throw new ApplicationException(string.Format( "found non-noded intersection at {0}-{1} and {2}-{3}", p00, p01, p10, p11)); } } }
/// <summary> /// A trivial intersection is an apparent self-intersection which in fact /// is simply the point shared by adjacent line segments. /// Note that closed edges require a special check for the point shared by the beginning and end segments. /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> /// <returns></returns> private bool IsTrivialIntersection(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1) { if (_li.IntersectionNum == 1) { if (IsAdjacentSegments(segIndex0, segIndex1)) { return(true); } if (e0.IsClosed) { int maxSegIndex = e0.Count - 1; if ((segIndex0 == 0 && segIndex1 == maxSegIndex) || (segIndex1 == 0 && segIndex0 == maxSegIndex)) { return(true); } } } } return(false); }
/// <summary> /// If an endpoint of one segment is near /// the <i>interior</i> of the other segment, add it as an intersection. /// EXCEPT if the endpoint is also close to a segment endpoint /// (since this can introduce "zigs" in the linework). /// <para/> /// This resolves situations where /// a segment A endpoint is extremely close to another segment B, /// but is not quite crossing.Due to robustness issues /// in orientation detection, this can /// result in the snapped segment A crossing segment B /// without a node being introduced. /// </summary> private void ProcessNearVertex(Coordinate p, ISegmentString edge, int segIndex, Coordinate p0, Coordinate p1) { /* * Don't add intersection if candidate vertex is near endpoints of segment. * This avoids creating "zig-zag" linework * (since the vertex could actually be outside the segment envelope). */ if (p.Distance(p0) < _nearnessTol) { return; } if (p.Distance(p1) < _nearnessTol) { return; } double distSeg = DistanceComputer.PointToSegment(p, p0, p1); if (distSeg < _nearnessTol) { Intersections.Add(p); ((NodedSegmentString)edge).AddIntersection(p, segIndex); } }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="ISegmentString" />s being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) return; Coordinate[] coordinates0 = e0.Coordinates; Coordinate p00 = coordinates0[segIndex0]; Coordinate p01 = coordinates0[segIndex0 + 1]; Coordinate[] coordinates1 = e1.Coordinates; Coordinate p10 = coordinates1[segIndex1]; Coordinate p11 = coordinates1[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (!_li.HasIntersection) return; if (!_li.IsInteriorIntersection()) return; for (int intIndex = 0; intIndex < _li.IntersectionNum; intIndex++) _interiorIntersections.Add(_li.GetIntersection(intIndex)); NodedSegmentString nss0 = (NodedSegmentString)e0; nss0.AddIntersections(_li, segIndex0, 0); NodedSegmentString nss1 = (NodedSegmentString)e1; nss1.AddIntersections(_li, segIndex1, 1); }
///<summary> /// A trivial intersection is an apparent self-intersection which in fact /// is simply the point shared by adjacent line segments. ///</summary> /// <remarks> /// Note that closed edges require a special check for the point shared by the beginning /// and end segments. /// </remarks> private bool IsTrivialIntersection(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1) { if (li.IntersectionNum == 1) { if (IsAdjacentSegments(segIndex0, segIndex1)) return true; if (e0.IsClosed) { int maxSegIndex = e0.Count - 1; if ((segIndex0 == 0 && segIndex1 == maxSegIndex) || (segIndex1 == 0 && segIndex0 == maxSegIndex)) { return true; } } } } return false; }
/// <summary> /// Dissolve the given <see cref="ISegmentString" />. /// </summary> /// <param name="segString"></param> public void Dissolve(ISegmentString segString) { OrientedCoordinateArray oca = new OrientedCoordinateArray(segString.Coordinates); ISegmentString existing = FindMatching(oca /*, segString*/); if (existing == null) Add(oca, segString); else { if (_merger != null) { bool isSameOrientation = CoordinateArrays.Equals(existing.Coordinates, segString.Coordinates); _merger.Merge(existing, segString, isSameOrientation); } } }
/// <summary> /// /// </summary> /// <param name="oca"></param> /// <param name="segString"></param> private void Add(OrientedCoordinateArray oca, ISegmentString segString) { _ocaMap.Add(oca, segString); }
private static void CheckCollapses(ISegmentString ss) { var pts = ss.Coordinates; for (var i = 0; i < pts.Length - 2; i++) CheckCollapse(pts[i], pts[i + 1], pts[i + 2]); }
/// <summary> /// /// </summary> /// <param name="nodeList"></param> NodeVertexIterator(SegmentNodeList nodeList) { _nodeList = nodeList; _edge = nodeList.Edge; _nodeIt = nodeList.GetEnumerator(); }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="ISegmentString" /> being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>") may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) return; NumTests++; Coordinate[] coordinates0 = e0.Coordinates; Coordinate p00 = coordinates0[segIndex0]; Coordinate p01 = coordinates0[segIndex0 + 1]; Coordinate[] coordinates1 = e1.Coordinates; Coordinate p10 = coordinates1[segIndex1]; Coordinate p11 = coordinates1[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if(_li.HasIntersection) { NumIntersections++; if (_li.IsInteriorIntersection()) { NumInteriorIntersections++; _hasInterior = true; } // if the segments are adjacent they have at least one trivial intersection, // the shared endpoint. Don't bother adding it if it is the // only intersection. if (!IsTrivialIntersection(e0, segIndex0, e1, segIndex1)) { _hasIntersection = true; ((NodedSegmentString)e0).AddIntersections(_li, segIndex0, 0); ((NodedSegmentString)e1).AddIntersections(_li, segIndex1, 1); if (_li.IsProper) { NumProperIntersections++; _hasProper = true; _hasProperInterior = true; } } } }
///<summary> /// This method is called by clients of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected. ///</summary> /// <remarks> /// Note that some clients (such as <see cref="MonotoneChain"/>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </remarks> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // don't intersect segment with itself if (e0 == e1 && segIndex0 == segIndex1) return; NumTests++; ICoordinate p00 = e0.Coordinates[segIndex0]; ICoordinate p01 = e0.Coordinates[segIndex0 + 1]; ICoordinate p10 = e1.Coordinates[segIndex1]; ICoordinate p11 = e1.Coordinates[segIndex1 + 1]; li.ComputeIntersection(p00, p01, p10, p11); //if (li.hasIntersection() && li.isProper()) Debug.println(li); if (li.HasIntersection) { //intersectionFound = true; NumIntersections++; if (li.IsInteriorIntersection()) { NumInteriorIntersections++; _hasInterior = true; //System.out.println(li); } // if the segments are adjacent they have at least one trivial intersection, // the shared endpoint. Don't bother adding it if it is the // only intersection. if (!IsTrivialIntersection(e0, segIndex0, e1, segIndex1)) { _hasIntersection = true; // only add intersection to test geom (the line) ((NodedSegmentString)e1).AddIntersections(li, segIndex1, 1); if (li.IsProper) { NumProperIntersections++; //Debug.println(li.toString()); Debug.println(li.getIntersection(0)); //properIntersectionPoint = (Coordinate) li.getIntersection(0).clone(); _hasProper = true; _hasProperInterior = true; } } } }
///<summary> /// Tests whether a segment in a <see cref="ISegmentString" /> is an end segment. /// (either the first or last). ///</summary> ///<param name="segStr">a segment string</param> ///<param name="index">the index of a segment in the segment string</param> ///<returns>true if the segment is an end segment</returns> private static Boolean IsEndSegment(ISegmentString segStr, int index) { if (index == 0) return true; if (index >= segStr.Count - 2) return true; return false; }
///<summary> /// This method is called by clients of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected.<br/> /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). ///</summary> ///<param name="e0"></param> ///<param name="segIndex0"></param> ///<param name="e1"></param> ///<param name="segIndex1"></param> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // short-circuit if intersection already found if (!FindAllIntersections && HasIntersection) return; // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) return; /* * If enabled, only test end segments (on either segString). * */ if (CheckEndSegmentsOnly) { Boolean isEndSegPresent = IsEndSegment(e0, segIndex0) || IsEndSegment(e1, segIndex1); if (!isEndSegPresent) return; } Coordinate p00 = e0.Coordinates[segIndex0]; Coordinate p01 = e0.Coordinates[segIndex0 + 1]; Coordinate p10 = e1.Coordinates[segIndex1]; Coordinate p11 = e1.Coordinates[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); if (_li.HasIntersection) { if (_li.IsInteriorIntersection()) { _intSegments = new Coordinate[4]; _intSegments[0] = p00; _intSegments[1] = p01; _intSegments[2] = p10; _intSegments[3] = p11; _interiorIntersection = _li.GetIntersection(0); if (KeepIntersections) _intersections.Add(_interiorIntersection); intersectionCount++; } } }
///<summary> /// This method is called by clients of the <see cref="ISegmentIntersector"/> class to process /// intersections for two segments of the <see cref="ISegmentString"/>s being intersected. ///</summary> /// <remarks> /// Note that some clients (such as <c>MonotoneChain</c>s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// </remarks> public void ProcessIntersections( ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1 ) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) return; var coords = e0.Coordinates; var p00 = coords[segIndex0]; var p01 = coords[segIndex0 + 1]; coords = e1.Coordinates; var p10 = coords[segIndex1]; var p11 = coords[segIndex1 + 1]; _li.ComputeIntersection(p00, p01, p10, p11); // if (li.hasIntersection() && li.isProper()) Debug.println(li); if (_li.HasIntersection) { // System.out.println(li); // record intersection info _hasIntersection = true; var isProper = _li.IsProper; if (isProper) _hasProperIntersection = true; if (!isProper) _hasNonProperIntersection = true; /* * If this is the kind of intersection we are searching for * OR no location has yet been recorded * save the location data */ var saveLocation = !(FindProper && !isProper); /* bool saveLocation = true; if (_findProper && !isProper) saveLocation = false; */ if (_intPt == null || saveLocation) { // record intersection location (approximate) _intPt = _li.GetIntersection(0); // record intersecting segments _intSegments = new Coordinate[4]; _intSegments[0] = p00; _intSegments[1] = p01; _intSegments[2] = p10; _intSegments[3] = p11; } } }
/// <summary> /// Creates a new instance from a <see cref="ISegmentString"/>. /// </summary> /// <param name="ss">The segment string to use.</param> public NodedSegmentString(ISegmentString ss) : this(ss.Coordinates, ss.Context) { //_pts = ss.Coordinates; //Context = ss.Context; }
/// <summary> /// Initializes a new instance of the <see cref="HotPixelSnapAction"/> class. /// </summary> /// <param name="hotPixel"></param> /// <param name="parentEdge"></param> /// <param name="hotPixelVertexIndex"></param> public HotPixelSnapAction(HotPixel hotPixel, ISegmentString parentEdge, int hotPixelVertexIndex) { _hotPixel = hotPixel; _parentEdge = parentEdge; _hotPixelVertexIndex = hotPixelVertexIndex; }