/// <summary> /// /// </summary> /// <param name="querySeg"></param> /// <returns></returns> public virtual IList Query(LineSegment querySeg) { Envelope env = new Envelope(querySeg.P0, querySeg.P1); LineSegmentVisitor visitor = new LineSegmentVisitor(querySeg); index.Query(env, visitor); IList itemsFound = visitor.Items; return itemsFound; }
/// <summary> /// /// </summary> private void BuildIndex() { _sirTree = new SIRtree(); IList<Coordinate> pts = _ring.Coordinates; for (int i = 1; i < pts.Count; i++) { if (pts[i-1].Equals(pts[i])) { continue; } LineSegment seg = new LineSegment(pts[i - 1], pts[i]); _sirTree.Insert(seg.P0.Y, seg.P1.Y, seg); } }
/// <summary> /// /// </summary> /// <param name="pts"></param> /// <param name="i"></param> /// <param name="j"></param> /// <param name="maxDistance"></param> /// <returns></returns> private static int FindFurthestPoint(IList<Coordinate> pts, int i, int j, double[] maxDistance) { LineSegment seg = new LineSegment(); seg.P0 = pts[i]; seg.P1 = pts[j]; double maxDist = -1.0; int maxIndex = i; for (int k = i + 1; k < j; k++) { Coordinate midPt = pts[k]; double distance = seg.Distance(midPt); if (distance > maxDist) { maxDist = distance; maxIndex = k; } } maxDistance[0] = maxDist; return maxIndex; }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="seg"></param> private void TestLineSegment(Coordinate p, LineSegment seg) { /* * Test if segment crosses ray from test point in positive x direction. */ Coordinate p1 = seg.CP0; Coordinate p2 = seg.cP1; double x1 = p1.X - p.X; double y1 = p1.Y - p.Y; double x2 = p2.X - p.X; double y2 = p2.Y - p.Y; if(((y1 > 0) && (y2 <= 0)) || ((y2 > 0) && (y1 <= 0))) { /* * segment straddles x axis, so compute intersection. */ double xInt = RobustDeterminant.SignOfDet2x2(x1, y1, x2, y2) / (y2 - y1); // x intersection of segment with ray /* * crosses ray if strictly positive intersection. */ if (0.0 < xInt) _crossings++; } }
/// <summary> /// /// </summary> /// <param name="seg"></param> public virtual void AddToResult(LineSegment seg) { _resultSegs.Add(seg); }
/// <summary> /// Given the specified test point, this checks each segment, and will /// return the closest point on the specified segment. /// </summary> /// <param name="testPoint">The point to test.</param> /// <returns></returns> public override Coordinate ClosestPoint(Coordinate testPoint) { Coordinate closest = Coordinate; double dist = double.MaxValue; for(int i = 0; i < _points.Count - 1; i++) { LineSegment s = new LineSegment(_points[i], _points[i+1]); Coordinate temp = s.ClosestPoint(testPoint); double tempDist = testPoint.Distance(temp); if(tempDist < dist) { dist = tempDist; closest = temp; } } return closest; }
/// <summary> /// /// </summary> /// <param name="line0"></param> /// <param name="line1"></param> /// <param name="locGeom"></param> private void ComputeMinDistance(ILineString line0, ILineString line1, GeometryLocation[] locGeom) { if (line0.EnvelopeInternal.Distance(line1.EnvelopeInternal) > _minDistance) return; IList<Coordinate> coord0 = line0.Coordinates; IList<Coordinate> coord1 = line1.Coordinates; // brute force approach! for (int i = 0; i < coord0.Count - 1; i++) { for (int j = 0; j < coord1.Count - 1; j++) { double dist = CGAlgorithms.DistanceLineLine( coord0[i], coord0[i + 1], coord1[j], coord1[j + 1]); if (dist < _minDistance) { _minDistance = dist; LineSegment seg0 = new LineSegment(coord0[i], coord0[i + 1]); LineSegment seg1 = new LineSegment(coord1[j], coord1[j + 1]); Coordinate[] closestPt = seg0.ClosestPoints(seg1); locGeom[0] = new GeometryLocation(line0, i, new Coordinate(closestPt[0])); locGeom[1] = new GeometryLocation(line1, j, new Coordinate(closestPt[1])); } if (_minDistance <= _terminateDistance) return; } } }
/// <summary> /// /// </summary> /// <param name="seg0"></param> /// <param name="seg1"></param> /// <returns></returns> private static bool HasInteriorIntersection(LineSegment seg0, LineSegment seg1) { Li.ComputeIntersection(seg0.CP0, seg0.cP1, seg1.CP0, seg1.cP1); return Li.IsInteriorIntersection(); }
/// <summary> /// /// </summary> /// <param name="candidateSeg"></param> /// <returns></returns> private bool HasBadOutputIntersection(LineSegment candidateSeg) { IList querySegs = _outputIndex.Query(candidateSeg); for (IEnumerator i = querySegs.GetEnumerator(); i.MoveNext(); ) { LineSegment querySeg = (LineSegment) i.Current; if (HasInteriorIntersection(querySeg, candidateSeg)) return true; } return false; }
/// <summary> /// /// </summary> /// <param name="geom"></param> private void ComputeWidthConvex(IGeometry geom) { IList<Coordinate> pts; if (geom is Polygon) pts = ((Polygon)geom).Shell.Coordinates; else pts = geom.Coordinates; // special cases for lines or points or degenerate rings if (pts.Count == 0) { _minWidth = 0.0; _minWidthPt = Coordinate.Empty; _minBaseSeg = null; } else if (pts.Count == 1) { _minWidth = 0.0; _minWidthPt = pts[0]; _minBaseSeg.P0 = pts[0]; _minBaseSeg.P1 = pts[0]; } else if (pts.Count == 2 || pts.Count == 3) { _minWidth = 0.0; _minWidthPt = pts[0]; _minBaseSeg.P0 = pts[0]; _minBaseSeg.P1 = pts[1]; } else ComputeConvexRingMinDiameter(pts); }
/// <summary> /// /// </summary> /// <param name="querySeg"></param> public LineSegmentVisitor(LineSegment querySeg) { this.querySeg = querySeg; }
/// <summary> /// /// </summary> /// <param name="seg"></param> public virtual void Remove(LineSegment seg) { index.Remove(new Envelope(seg.P0, seg.P1), seg); }
/// <summary> /// /// </summary> /// <param name="seg"></param> public virtual void Add(LineSegment seg) { index.Insert(new Envelope(seg.P0, seg.P1), seg); }
/// <summary> /// /// </summary> /// <param name="index"></param> /// <param name="ls"></param> public virtual void GetLineSegment(int index, ref LineSegment ls) { ls.P0 = _pts[index]; ls.P1 = _pts[index + 1]; }
/// <summary> /// This is a convenience function which can be overridden to obtain the actual /// line segment which is selected. /// </summary> /// <param name="seg"></param> public virtual void Select(LineSegment seg) { }
/// <summary> /// /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> private LineSegment Flatten(int start, int end) { // make a new segment for the simplified point Coordinate p0 = _linePts[start]; Coordinate p1 = _linePts[end]; LineSegment newSeg = new LineSegment(p0, p1); // update the indexes Remove(_line, start, end); _outputIndex.Add(newSeg); return newSeg; }
/// <summary> /// /// </summary> /// <param name="parentLine"></param> /// <param name="sectionIndex"></param> /// <param name="candidateSeg"></param> /// <returns></returns> private bool HasBadIntersection(TaggedLineString parentLine, int[] sectionIndex, LineSegment candidateSeg) { if (HasBadOutputIntersection(candidateSeg)) return true; if (HasBadInputIntersection(parentLine, sectionIndex, candidateSeg)) return true; return false; }
/// <summary> /// Compute the width information for a ring of <c>Coordinate</c>s. /// Leaves the width information in the instance variables. /// </summary> /// <param name="pts"></param> private void ComputeConvexRingMinDiameter(IList<Coordinate> pts) { // for each segment in the ring _minWidth = Double.MaxValue; int currMaxIndex = 1; LineSegment seg = new LineSegment(); // compute the max distance for all segments in the ring, and pick the minimum for (int i = 0; i < pts.Count - 1; i++) { seg.P0 = pts[i]; seg.P1 = pts[i + 1]; currMaxIndex = FindMaxPerpDistance(pts, seg, currMaxIndex); } }
/// <summary> /// /// </summary> /// <param name="parentLine"></param> /// <param name="sectionIndex"></param> /// <param name="candidateSeg"></param> /// <returns></returns> private bool HasBadInputIntersection(TaggedLineString parentLine, int[] sectionIndex, LineSegment candidateSeg) { IList querySegs = _inputIndex.Query(candidateSeg); for (IEnumerator i = querySegs.GetEnumerator(); i.MoveNext(); ) { TaggedLineSegment querySeg = (TaggedLineSegment) i.Current; if (HasInteriorIntersection(querySeg, candidateSeg)) { if (IsInLineSection(parentLine, sectionIndex, querySeg)) continue; return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="pts"></param> /// <param name="seg"></param> /// <param name="startIndex"></param> /// <returns></returns> private int FindMaxPerpDistance(IList<Coordinate> pts, ILineSegment seg, int startIndex) { double maxPerpDistance = seg.DistancePerpendicular(pts[startIndex]); double nextPerpDistance = maxPerpDistance; int maxIndex = startIndex; int nextIndex = maxIndex; while (nextPerpDistance >= maxPerpDistance) { maxPerpDistance = nextPerpDistance; maxIndex = nextIndex; nextIndex = NextIndex(pts, maxIndex); nextPerpDistance = seg.DistancePerpendicular(pts[nextIndex]); } // found maximum width for this segment - update global min dist if appropriate if (maxPerpDistance < _minWidth) { _minPtIndex = maxIndex; _minWidth = maxPerpDistance; _minWidthPt = pts[_minPtIndex]; _minBaseSeg = new LineSegment(seg); } return maxIndex; }
/// <summary> /// /// </summary> /// <param name="i"></param> /// <param name="j"></param> /// <param name="depth"></param> private void SimplifySection(int i, int j, int depth) { depth += 1; int[] sectionIndex = new int[2]; if((i+1) == j) { LineSegment newSeg = _line.GetSegment(i); _line.AddToResult(newSeg); // leave this segment in the input index, for efficiency return; } double[] distance = new double[1]; int furthestPtIndex = FindFurthestPoint(_linePts, i, j, distance); bool isValidToFlatten = true; // must have enough points in the output line if (_line.ResultSize < _line.MinimumSize && depth < 2) isValidToFlatten = false; // flattening must be less than distanceTolerance if (distance[0] > DistanceTolerance) isValidToFlatten = false; // test if flattened section would cause intersection LineSegment candidateSeg = new LineSegment(); candidateSeg.P0 = _linePts[i]; candidateSeg.P1 = _linePts[j]; sectionIndex[0] = i; sectionIndex[1] = j; if (HasBadIntersection(_line, sectionIndex, candidateSeg)) isValidToFlatten = false; if (isValidToFlatten) { LineSegment newSeg = Flatten(i, j); _line.AddToResult(newSeg); return; } SimplifySection(i, furthestPtIndex, depth); SimplifySection(furthestPtIndex, j, depth); }
/// <summary> /// /// </summary> /// <param name="seg"></param> /// <param name="depth"></param> public DepthSegment(ILineSegmentBase seg, int depth) { // input seg is assumed to be normalized _upwardSeg = new LineSegment(seg); _leftDepth = depth; }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="pt"></param> /// <param name="locGeom"></param> private void ComputeMinDistance(ILineString line, Point pt, GeometryLocation[] locGeom) { if (line.EnvelopeInternal.Distance(pt.EnvelopeInternal) > _minDistance) return; IList<Coordinate> coord0 = line.Coordinates; Coordinate coord = pt.Coordinate; // brute force approach! for (int i = 0; i < coord0.Count - 1; i++) { double dist = CGAlgorithms.DistancePointLine(coord, coord0[i], coord0[i + 1]); if (dist < _minDistance) { _minDistance = dist; LineSegment seg = new LineSegment(coord0[i], coord0[i + 1]); Coordinate segClosestPoint = new Coordinate(seg.ClosestPoint(coord)); locGeom[0] = new GeometryLocation(line, i, segClosestPoint); locGeom[1] = new GeometryLocation(pt, 0, coord); } if (_minDistance <= _terminateDistance) return; } }
/// <summary> /// Compare two collinear segments for left-most ordering. /// If segs are vertical, use vertical ordering for comparison. /// If segs are equal, return 0. /// Segments are assumed to be directed so that the second coordinate is >= to the first /// (e.g. up and to the right). /// </summary> /// <param name="seg0">A segment to compare.</param> /// <param name="seg1">A segment to compare.</param> /// <returns></returns> private static int CompareX(LineSegment seg0, ILineSegmentBase seg1) { int compare0 = seg0.CP0.CompareTo(seg1.P0); if (compare0 != 0) return compare0; return seg0.cP1.CompareTo(seg1.P1); }
/// <summary> /// Computes the closest points on a line segment. /// </summary> /// <param name="line"></param> /// <returns> /// A pair of Coordinates which are the closest points on the line segments. /// </returns> public virtual Coordinate[] ClosestPoints(ILineSegmentBase line) { LineSegment myLine = new LineSegment(line); // test for intersection Coordinate intPt = Intersection(line); if (intPt != null) return new[] {intPt, intPt}; /* * if no intersection closest pair contains at least one endpoint. * Test each endpoint in turn. */ Coordinate[] closestPt = new Coordinate[2]; Coordinate close00 = new Coordinate(ClosestPoint(line.P0)); double minDistance = close00.Distance(line.P0); closestPt[0] = close00; closestPt[1] = new Coordinate(line.P0); Coordinate close01 = new Coordinate(ClosestPoint(line.P1)); double dist = close01.Distance(line.P1); if (dist < minDistance) { minDistance = dist; closestPt[0] = close01; closestPt[1] = new Coordinate(line.P1); } Coordinate close10 = new Coordinate(myLine.ClosestPoint(P0)); dist = close10.Distance(P0); if (dist < minDistance) { minDistance = dist; closestPt[0] = new Coordinate(P0); closestPt[1] = close10; } Coordinate close11 = new Coordinate(myLine.ClosestPoint(P1)); dist = close11.Distance(P1); if (dist < minDistance) { closestPt[0] = new Coordinate(P1); closestPt[1] = close11; } return closestPt; }
/// <summary> /// This is a convenience function which can be overridden to obtain the actual /// line segments which overlap. /// </summary> /// <param name="seg1"></param> /// <param name="seg2"></param> public virtual void Overlap(LineSegment seg1, LineSegment seg2) { }
/// <summary> /// Creates a new vector from a line segment, assuming that the direction is from the start point to the end point /// </summary> /// <param name="inLineSegment">A Topology.LineSegment object to turn into a vector</param> public Vector(LineSegment inLineSegment) { X = inLineSegment.P1.X - inLineSegment.P0.X; Y = inLineSegment.P1.Y - inLineSegment.P0.Y; Z = inLineSegment.P1.Z - inLineSegment.P0.Z; }
/// <summary> /// /// </summary> /// <param name="ls"></param> public override void Select(LineSegment ls) { _container.TestLineSegment(_p, ls); }