/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="SegmentString" />s being intersected. /// 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). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) { return; } 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) { if (li.IsInteriorIntersection()) { for (int intIndex = 0; intIndex < li.IntersectionNum; intIndex++) { interiorIntersections.Add(li.GetIntersection(intIndex)); } e0.AddIntersections(li, segIndex0, 0); e1.AddIntersections(li, segIndex1, 1); } } }
/// <summary> /// /// </summary> /// <param name="mc1"></param> /// <param name="start1"></param> /// <param name="mc2"></param> /// <param name="start2"></param> public override void Overlap(MonotoneChain mc1, int start1, MonotoneChain mc2, int start2) { SegmentString ss1 = (SegmentString)mc1.Context; SegmentString ss2 = (SegmentString)mc2.Context; si.ProcessIntersections(ss1, start1, ss2, start2); }
/// <summary> /// /// </summary> /// <param name="ss0"></param> /// <param name="ss1"></param> private void CheckInteriorIntersections(SegmentString ss0, SegmentString ss1) { ICoordinate[] pts0 = ss0.Coordinates; ICoordinate[] 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> /// /// </summary> /// <param name="ss"></param> private void CheckCollapses(SegmentString ss) { ICoordinate[] pts = ss.Coordinates; for (int i = 0; i < pts.Length - 2; i++) { CheckCollapse(pts[i], pts[i + 1], pts[i + 2]); } }
/// <summary> /// Initializes a new instance of the <see cref="SegmentNode"/> class. /// </summary> /// <param name="segString"></param> /// <param name="coord"></param> /// <param name="segmentIndex"></param> /// <param name="segmentOctant"></param> public SegmentNode(SegmentString segString, ICoordinate coord, int segmentIndex, Octants segmentOctant) { this.segString = segString; this.Coordinate = new Coordinate(coord); this.SegmentIndex = segmentIndex; this.segmentOctant = segmentOctant; isInterior = !coord.Equals2D(segString.GetCoordinate(segmentIndex)); }
/// <summary> /// /// </summary> /// <param name="segStrings"></param> /// <returns></returns> private IList Scale(IList segStrings) { return(CollectionUtil.Transform(segStrings, delegate(object obj) { SegmentString ss = (SegmentString)obj; return new SegmentString(Scale(ss.Coordinates), ss.Data); })); }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="e1"></param> private void ComputeIntersects(SegmentString e0, SegmentString e1) { ICoordinate[] pts0 = e0.Coordinates; ICoordinate[] 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); }
/// <summary> /// /// </summary> /// <param name="segStrings"></param> /// <param name="resultEdgelist"></param> public static void GetNodedSubstrings(IList segStrings, IList resultEdgelist) { foreach (object obj in segStrings) { SegmentString ss = (SegmentString)obj; ss.NodeList.AddSplitEdges(resultEdgelist); } }
/// <summary> /// Creates a {SegmentString} for a coordinate list which is a raw offset curve, /// and adds it to the list of buffer curves. /// The SegmentString is tagged with a Label giving the topology of the curve. /// The curve may be oriented in either direction. /// If the curve is oriented CW, the locations will be: /// Left: Location.Exterior. /// Right: Location.Interior. /// </summary> private void AddCurve(ICoordinate[] coord, Locations leftLoc, Locations rightLoc) { // don't add null curves! if (coord.Length < 2) return; // add the edge for a coordinate list which is a raw offset curve SegmentString e = new SegmentString(coord, new Label(0, Locations.Boundary, leftLoc, rightLoc)); curveList.Add(e); }
/// <summary> /// /// </summary> /// <param name="segStrings"></param> private void Rescale(IList segStrings) { CollectionUtil.Apply(segStrings, delegate(object obj) { SegmentString ss = (SegmentString)obj; Rescale(ss.Coordinates); return(null); }); }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="e1"></param> private void ComputeIntersects(SegmentString e0, SegmentString e1) { ICoordinate[] pts0 = e0.Coordinates; ICoordinate[] 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); } } }
/// <summary> /// /// </summary> /// <param name="segStr"></param> private void Add(SegmentString segStr) { IList segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (object obj in segChains) { MonotoneChain mc = (MonotoneChain)obj; mc.Id = idCounter++; index.Insert(mc.Envelope, mc); monoChains.Add(mc); } }
/// <summary> /// /// </summary> /// <param name="ss0"></param> /// <param name="ss1"></param> private void CheckInteriorIntersections(SegmentString ss0, SegmentString ss1) { ICoordinate[] pts0 = ss0.Coordinates; ICoordinate[] 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> /// Computes the noding for a collection of <see cref="SegmentString" />s. /// Some Noders may add all these nodes to the input <see cref="SegmentString" />s; /// others may only add some or none at all. /// </summary> /// <param name="inputSegStrings"></param> public override void ComputeNodes(IList inputSegStrings) { this.nodedSegStrings = inputSegStrings; foreach (object obj0 in inputSegStrings) { SegmentString edge0 = (SegmentString)obj0; foreach (object obj1 in inputSegStrings) { SegmentString edge1 = (SegmentString)obj1; ComputeIntersects(edge0, edge1); } } }
/// <summary> /// Dissolve the given <see cref="SegmentString" />. /// </summary> /// <param name="segString"></param> public void Dissolve(SegmentString segString) { OrientedCoordinateArray oca = new OrientedCoordinateArray(segString.Coordinates); SegmentString 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); } } }
private void CheckInteriorIntersections(SegmentString e0, int segIndex0, SegmentString 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> /// Dissolve the given <see cref="SegmentString" />. /// </summary> /// <param name="segString"></param> public void Dissolve(SegmentString segString) { OrientedCoordinateArray oca = new OrientedCoordinateArray(segString.Coordinates); SegmentString 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> /// Creates new edges for all the edges that the intersections in this /// list split the parent edge into. /// Adds the edges to the provided argument list /// (this is so a single list can be used to accumulate all split edges /// for a set of <see cref="SegmentString" />s). /// </summary> /// <param name="edgeList"></param> public void AddSplitEdges(IList edgeList) { // ensure that the list has entries for the first and last point of the edge AddEndPoints(); AddCollapsedNodes(); IEnumerator ie = GetEnumerator(); ie.MoveNext(); // there should always be at least two entries in the list, since the endpoints are nodes SegmentNode eiPrev = (SegmentNode)ie.Current; while (ie.MoveNext()) { SegmentNode ei = (SegmentNode)ie.Current; SegmentString newEdge = CreateSplitEdge(eiPrev, ei); edgeList.Add(newEdge); eiPrev = ei; } }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="SegmentString" /> being intersected. /// 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). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { 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) { 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; e0.AddIntersections(li, segIndex0, 0); e1.AddIntersections(li, segIndex1, 1); if (li.IsProper) { NumProperIntersections++; hasProper = true; hasProperInterior = true; } } } }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> private void CheckInteriorIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) { return; } 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) { if (li.IsProper || HasInteriorIntersection(li, p00, p01) || HasInteriorIntersection(li, p10, p11)) { throw new Exception("found non-noded intersection at " + p00 + "-" + p01 + " and " + p10 + "-" + p11); } } }
private void CheckInteriorIntersections(SegmentString e0, int segIndex0, SegmentString 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(SegmentString e0, int segIndex0, SegmentString 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> /// /// </summary> /// <param name="splitEdges"></param> private void CheckSplitEdgesCorrectness(IList splitEdges) { ICoordinate[] edgePts = edge.Coordinates; // check that first and last points of split edges are same as endpoints of edge SegmentString split0 = (SegmentString)splitEdges[0]; ICoordinate pt0 = split0.GetCoordinate(0); if (!pt0.Equals2D(edgePts[0])) { throw new Exception("bad split edge start point at " + pt0); } SegmentString splitn = (SegmentString)splitEdges[splitEdges.Count - 1]; ICoordinate[] splitnPts = splitn.Coordinates; ICoordinate ptn = splitnPts[splitnPts.Length - 1]; if (!ptn.Equals2D(edgePts[edgePts.Length - 1])) { throw new Exception("bad split edge end point at " + ptn); } }
/// <summary> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="SegmentString" />s being intersected. /// 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). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1 ) { // don't bother intersecting a segment with itself if (e0 == e1 && segIndex0 == segIndex1) return; 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) { if (li.IsInteriorIntersection()) { for(int intIndex = 0; intIndex < li.IntersectionNum; intIndex++) interiorIntersections.Add(li.GetIntersection(intIndex)); e0.AddIntersections(li, segIndex0, 0); e1.AddIntersections(li, segIndex1, 1); } } }
private SegmentString edge = null; // the parent edge /// <summary> /// Initializes a new instance of the <see cref="SegmentNodeList"/> class. /// </summary> /// <param name="edge">The edge.</param> public SegmentNodeList(SegmentString edge) { this.edge = edge; }
/// <summary> /// /// </summary> /// <param name="oca"></param> /// <param name="segString"></param> /// <returns></returns> private SegmentString FindMatching(OrientedCoordinateArray oca, SegmentString segString) { return((SegmentString)ocaMap[oca]); }
/// <summary> /// /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> private void CheckInteriorIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) return; 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) if (li.IsProper || HasInteriorIntersection(li, p00, p01) || HasInteriorIntersection(li, p10, p11)) throw new Exception("found non-noded intersection at " + p00 + "-" + p01 + " and " + p10 + "-" + p11); }
/// <summary> /// /// </summary> /// <param name="oca"></param> /// <param name="segString"></param> private void Add(OrientedCoordinateArray oca, SegmentString segString) { ocaMap.Add(oca, segString); }
/// <summary> /// /// </summary> /// <param name="ss"></param> private void CheckCollapses(SegmentString ss) { ICoordinate[] pts = ss.Coordinates; for (int i = 0; i < pts.Length - 2; i++) CheckCollapse(pts[i], pts[i + 1], pts[i + 2]); }
/// <summary> /// /// </summary> /// <param name="segStr"></param> private void Add(SegmentString segStr) { var segChains = MonotoneChainBuilder.GetChains(segStr.Coordinates, segStr); foreach (var obj in segChains) { var mc = (MonotoneChain)obj; mc.Id = idCounter++; index.Insert(mc.Envelope, mc); monoChains.Add(mc); } }
/// <summary> /// Returns a <see cref="IList"/> of fully noded <see cref="SegmentString"/>s. /// The <see cref="SegmentString"/>s have the same context as their parent. /// </summary> /// <returns></returns> public override IList GetNodedSubstrings() { return(SegmentString.GetNodedSubstrings(nodedSegStrings)); }
/// <summary> /// /// </summary> /// <param name="nodeList"></param> NodeVertexIterator(SegmentNodeList nodeList) { this.nodeList = nodeList; edge = nodeList.Edge; nodeIt = nodeList.GetEnumerator(); }
/// <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(SegmentString e0, int segIndex0, SegmentString 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> /// This method is called by clients /// of the <see cref="ISegmentIntersector" /> class to process /// intersections for two segments of the <see cref="SegmentString" /> being intersected. /// 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). /// </summary> /// <param name="e0"></param> /// <param name="segIndex0"></param> /// <param name="e1"></param> /// <param name="segIndex1"></param> public void ProcessIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { 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) { 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; e0.AddIntersections(li, segIndex0, 0); e1.AddIntersections(li, segIndex1, 1); if (li.IsProper) { NumProperIntersections++; hasProper = true; hasProperInterior = true; } } } }
/// <summary> /// /// </summary> /// <param name="oca"></param> /// <param name="segString"></param> /// <returns></returns> private SegmentString FindMatching(OrientedCoordinateArray oca, SegmentString segString) { return (SegmentString)ocaMap[oca]; }