public LocateFailureException(LineSegment seg) : base("Locate failed to converge (at edge: " + seg + "). Possible causes include invalid Subdivision topology or very close sites") { this.Segment = new LineSegment(seg); }
/// <summary> /// Densifies a coordinate sequence. /// </summary> /// <param name="pts">The coordinate sequence to densify</param> /// <param name="distanceTolerance">The distance tolerance (<see cref="DistanceTolerance"/>)</param> /// <param name="precModel">The precision model to apply on the new coordinates</param> /// <returns>The densified coordinate sequence</returns> private static Coordinate[] DensifyPoints(Coordinate[] pts, double distanceTolerance, IPrecisionModel precModel) { var seg = new LineSegment(); var coordList = new CoordinateList(); for (int i = 0; i < pts.Length - 1; i++) { seg.P0 = pts[i]; seg.P1 = pts[i + 1]; coordList.Add(seg.P0, false); double len = seg.Length; int densifiedSegCount = (int) (len/distanceTolerance) + 1; if (densifiedSegCount > 1) { double densifiedSegLen = len/densifiedSegCount; for (int j = 1; j < densifiedSegCount; j++) { double segFract = (j*densifiedSegLen)/len; var p = seg.PointAlong(segFract); precModel.MakePrecise(p); coordList.Add(p, false); } } } coordList.Add(pts[pts.Length - 1], false); return coordList.ToCoordinateArray(); }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="seg"></param> private void TestLineSegment(Coordinate p, LineSegment seg) { double xInt; // x intersection of segment with ray double x1; // translated coordinates double y1; double x2; double y2; /* * Test if segment crosses ray from test point in positive x direction. */ Coordinate p1 = seg.P0; Coordinate p2 = seg.P1; x1 = p1.X - p.X; y1 = p1.Y - p.Y; x2 = p2.X - p.X; y2 = p2.Y - p.Y; if (((y1 > 0) && (y2 <= 0)) || ((y2 > 0) && (y1 <= 0))) { /* * segment straddles x axis, so compute intersection. */ xInt = RobustDeterminant.SignOfDet2x2(x1, y1, x2, y2) / (y2 - y1); /* * crosses ray if strictly positive intersection. */ if (0.0 < xInt) _crossings++; } }
void CheckOffset(double x0, double y0, double x1, double y1, double segFrac, double offset, double expectedX, double expectedY) { LineSegment seg = new LineSegment(x0, y0, x1, y1); Coordinate p = seg.PointAlongOffset(segFrac, offset); Assert.IsTrue(EqualsTolerance(new Coordinate(expectedX, expectedY), p, 0.000001)); }
private Coordinate computePoint(LineSegment seg, double dist) { double dx = seg.P1.X - seg.P0.X; double dy = seg.P1.Y - seg.P0.Y; double len = seg.Length; Coordinate pt = new Coordinate(dist * dx / len, dist * dy / len); pm.MakePrecise(pt); return pt; }
public void TestProjectionFactor() { // zero-length line var seg = new LineSegment(10, 0, 10, 0); Assert.IsTrue(Double.IsNaN(seg.ProjectionFactor(new Coordinate(11, 0)))); var seg2 = new LineSegment(10, 0, 20, 0); Assert.IsTrue(seg2.ProjectionFactor(new Coordinate(11, 0)) == 0.1); }
private void UpdateClearance(double candidateValue, Coordinate p, Coordinate seg0, Coordinate seg1) { if (candidateValue < _minClearance) { _minClearance = candidateValue; _minClearancePts[0] = new Coordinate(p); var seg = new LineSegment(seg0, seg1); _minClearancePts[1] = new Coordinate(seg.ClosestPoint(p)); } }
public static void ComputeDistance(ILineString line, Coordinate pt, PointPairDistance ptDist) { var coords = line.Coordinates; var tempSegment = new LineSegment(); for (var i = 0; i < coords.Length - 1; i++) { tempSegment.SetCoordinates(coords[i], coords[i + 1]); // this is somewhat inefficient - could do better var closestPt = tempSegment.ClosestPoint(pt); ptDist.SetMinimum(closestPt, pt); } }
/// <summary> /// /// </summary> private void BuildIndex() { _sirTree = new SIRtree<LineSegment>(); Coordinate[] pts = _ring.Coordinates; for (int i = 1; i < pts.Length; 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); } }
private void CheckPointsAtDistance(LineSegment seg, double dist0, double dist1) { Coordinate p0 = computePoint(seg, dist0); Coordinate p1 = computePoint(seg, dist1); if (p0.Equals(p1)) { CheckNodePosition(seg, p0, p1, 0); } else { CheckNodePosition(seg, p0, p1, -1); CheckNodePosition(seg, p1, p0, 1); } }
public void TestOrientationIndexCoordinate() { LineSegment seg = new LineSegment(0, 0, 10, 10); CheckOrientationIndex(seg, 10, 11, 1); CheckOrientationIndex(seg, 10, 9, -1); CheckOrientationIndex(seg, 11, 11, 0); CheckOrientationIndex(seg, 11, 11.0000001, 1); CheckOrientationIndex(seg, 11, 10.9999999, -1); CheckOrientationIndex(seg, -2, -1.9999999, 1); CheckOrientationIndex(seg, -2, -2.0000001, -1); }
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; } bool isValidToSimplify = true; /** * Following logic ensures that there is enough points in the output line. * If there is already more points than the minimum, there's nothing to check. * Otherwise, if in the worst case there wouldn't be enough points, * don't flatten this segment (which avoids the worst case scenario) */ if (_line.ResultSize < _line.MinimumSize) { int worstCaseSize = depth + 1; if (worstCaseSize < _line.MinimumSize) isValidToSimplify = false; } double[] distance = new double[1]; int furthestPtIndex = FindFurthestPoint(_linePts, i, j, distance); // flattening must be less than distanceTolerance if (distance[0] > _distanceTolerance) isValidToSimplify = 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)) isValidToSimplify = false; if (isValidToSimplify) { LineSegment newSeg = Flatten(i, j); _line.AddToResult(newSeg); return; } SimplifySection(i, furthestPtIndex, depth); SimplifySection(furthestPtIndex, j, depth); }
private void CheckSegment(double x, double y) { Coordinate seg0 = new Coordinate(0, 0); Coordinate seg1 = new Coordinate(x, y); LineSegment seg = new LineSegment(seg0, seg1); for (int i = 0; i < 4; i++) { double dist = i; double gridSize = 1 / pm.Scale; CheckPointsAtDistance(seg, dist, dist + 1.0 * gridSize); CheckPointsAtDistance(seg, dist, dist + 2.0 * gridSize); CheckPointsAtDistance(seg, dist, dist + 3.0 * gridSize); CheckPointsAtDistance(seg, dist, dist + 4.0 * gridSize); } }
/// <summary> /// Gets the line segment starting at <paramref name="index"/> /// </summary> /// <param name="index">The index of the segment</param> /// <param name="ls">The line segment to extract to</param> public 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 segments which overlap. /// </summary> /// <param name="seg1"></param> /// <param name="seg2"></param> public virtual void Overlap(LineSegment seg1, LineSegment seg2) { }
/// <summary> /// /// </summary> /// <param name="ls"></param> public override void Select(LineSegment ls) { _container.TestLineSegment(_p, ls); }
/// <summary> /// Returns <c>true</c> if <c>other</c> is /// topologically equal to this LineSegment (e.g. irrespective /// of orientation). /// </summary> /// <param name="other"> /// A <c>LineSegment</c> with which to do the comparison. /// </param> /// <returns> /// <c>true</c> if <c>other</c> is a <c>LineSegment</c> /// with the same values for the x and y ordinates. /// </returns> public bool EqualsTopologically(LineSegment other) { return(_p0.Equals(other._p0) && _p1.Equals(other._p1) || _p0.Equals(other._p1) && _p1.Equals(other._p0)); }
/// <summary> /// /// </summary> /// <param name="ls"></param> public void SetCoordinates(LineSegment ls) { SetCoordinates(ls._p0, ls._p1); }
/// <summary> /// Returns <c>true</c> if <c>other</c> is /// topologically equal to this LineSegment (e.g. irrespective /// of orientation). /// </summary> /// <param name="other"> /// A <c>LineSegment</c> with which to do the comparison. /// </param> /// <returns> /// <c>true</c> if <c>other</c> is a <c>LineSegment</c> /// with the same values for the x and y ordinates. /// </returns> public bool EqualsTopologically(LineSegment other) { return _p0.Equals(other._p0) && _p1.Equals(other._p1) || _p0.Equals(other._p1) && _p1.Equals(other._p0); }
/// <summary> /// Computes an intersection point between two segments, if there is one. /// There may be 0, 1 or many intersection points between two segments. /// If there are 0, null is returned. If there is 1 or more, a single one /// is returned (chosen at the discretion of the algorithm). If /// more information is required about the details of the intersection, /// the {RobustLineIntersector} class should be used. /// </summary> /// <param name="line">A line segment</param> /// <returns> An intersection point, or <c>null</c> if there is none.</returns> /// <see cref="RobustLineIntersector"/> public Coordinate Intersection(LineSegment line) { LineIntersector li = new RobustLineIntersector(); li.ComputeIntersection(_p0, _p1, line._p0, line._p1); if (li.HasIntersection) return li.GetIntersection(0); return null; }
/// <summary> /// Project a line segment onto this line segment and return the resulting /// line segment. The returned line segment will be a subset of /// the target line line segment. This subset may be null, if /// the segments are oriented in such a way that there is no projection. /// Note that the returned line may have zero length (i.e. the same endpoints). /// This can happen for instance if the lines are perpendicular to one another. /// </summary> /// <param name="seg">The line segment to project.</param> /// <returns>The projected line segment, or <c>null</c> if there is no overlap.</returns> public LineSegment Project(LineSegment seg) { var pf0 = ProjectionFactor(seg._p0); var pf1 = ProjectionFactor(seg._p1); // check if segment projects at all if (pf0 >= 1.0 && pf1 >= 1.0) return null; if (pf0 <= 0.0 && pf1 <= 0.0) return null; var newp0 = Project(seg._p0); if (pf0 < 0.0) newp0 = _p0; if (pf0 > 1.0) newp0 = _p1; var newp1 = Project(seg._p1); if (pf1 < 0.0) newp1 = _p0; if (pf1 > 1.0) newp1 = _p1; return new LineSegment(newp0, newp1); }
/// <summary> /// Computes the distance between this line segment and another one. /// </summary> /// <param name="ls"></param> /// <returns></returns> public double Distance(LineSegment ls) { return(CGAlgorithms.DistanceLineLine(_p0, _p1, ls._p0, ls._p1)); }
/// <summary> /// Creates an instance of this class using another instance /// </summary> /// <param name="ls"></param> public LineSegment(LineSegment ls) : this(ls._p0, ls._p1) { }
/// <summary> /// Determines the orientation of a LineSegment relative to this segment. /// The concept of orientation is specified as follows: /// Given two line segments A and L, /// A is to the left of a segment L if A lies wholly in the /// closed half-plane lying to the left of L /// A is to the right of a segment L if A lies wholly in the /// closed half-plane lying to the right of L /// otherwise, A has indeterminate orientation relative to L. This /// happens if A is collinear with L or if A crosses the line determined by L. /// </summary> /// <param name="seg">The <c>LineSegment</c> to compare.</param> /// <returns> /// 1 if <c>seg</c> is to the left of this segment, /// -1 if <c>seg</c> is to the right of this segment, /// 0 if <c>seg</c> has indeterminate orientation relative to this segment. /// </returns> public int OrientationIndex(LineSegment seg) { var orient0 = CGAlgorithms.OrientationIndex(_p0, _p1, seg._p0); var orient1 = CGAlgorithms.OrientationIndex(_p0, _p1, seg._p1); // this handles the case where the points are Curve or collinear if (orient0 >= 0 && orient1 >= 0) return Math.Max(orient0, orient1); // this handles the case where the points are R or collinear if (orient0 <= 0 && orient1 <= 0) return Math.Max(orient0, orient1); // points lie on opposite sides ==> indeterminate orientation return 0; }
/// <summary> /// Computes the distance between this line segment and another one. /// </summary> /// <param name="ls"></param> /// <returns></returns> public double Distance(LineSegment ls) { return CGAlgorithms.DistanceLineLine(_p0, _p1, ls._p0, ls._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 Coordinate[] ClosestPoints(LineSegment line) { // test for intersection var 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. */ var closestPt = new Coordinate[2]; var close00 = ClosestPoint(line._p0); double minDistance = close00.Distance(line._p0); closestPt[0] = close00; closestPt[1] = line._p0; var close01 = ClosestPoint(line._p1); double dist = close01.Distance(line._p1); if (dist < minDistance) { minDistance = dist; closestPt[0] = close01; closestPt[1] = line._p1; } var close10 = line.ClosestPoint(_p0); dist = close10.Distance(_p0); if (dist < minDistance) { minDistance = dist; closestPt[0] = _p0; closestPt[1] = close10; } var close11 = line.ClosestPoint(_p1); dist = close11.Distance(_p1); if (dist < minDistance) { minDistance = dist; closestPt[0] = _p1; closestPt[1] = close11; } return closestPt; }
/// <summary> /// Adds a mitre join connecting the two reflex offset segments. /// The mitre will be beveled if it exceeds the mitre ratio limit. /// </summary> /// <param name="p"></param> /// <param name="offset0">The first offset segment</param> /// <param name="offset1">The second offset segment</param> /// <param name="distance">The offset distance</param> private void AddMitreJoin(Coordinate p, LineSegment offset0, LineSegment offset1, double distance) { var isMitreWithinLimit = true; Coordinate intPt; /** * This computation is unstable if the offset segments are nearly collinear. * Howver, this situation should have been eliminated earlier by the check for * whether the offset segment endpoints are almost coincident */ try { intPt = HCoordinate.Intersection(offset0.P0, offset0.P1, offset1.P0, offset1.P1); var mitreRatio = distance <= 0.0 ? 1.0 : intPt.Distance(p) / Math.Abs(distance); if (mitreRatio > _bufParams.MitreLimit) isMitreWithinLimit = false; } catch (NotRepresentableException ex) { intPt = new Coordinate(0, 0); isMitreWithinLimit = false; } if (isMitreWithinLimit) { _segList.AddPt(intPt); } else { AddLimitedMitreJoin(offset0, offset1, distance, _bufParams.MitreLimit); // addBevelJoin(offset0, offset1); } }
/// <summary> /// Computes the intersection point of the lines defined by two segments, if there is one. /// </summary> /// <remarks> /// There may be 0, 1 or an infinite number of intersection points between two lines. /// If there is a unique intersection point, it is returned. /// Otherwise, <c>null</c> is returned. /// If more information is required about the details of the intersection, /// the <see cref="RobustLineIntersector"/> class should be used. /// </remarks> /// <param name="line">A line segment defining a straight line</param> /// <returns>An intersection point, or <c>null</c> if there is none or an infinite number</returns> /// <seealso cref="RobustLineIntersector"/> public Coordinate LineIntersection(LineSegment line) { try { var intPt = HCoordinate.Intersection(_p0, _p1, line._p0, line._p1); return intPt; } catch (NotRepresentableException ex) { // eat this exception, and return null; } return null; }
/// <summary> /// Adds a limited mitre join connecting the two reflex offset segments. /// A limited mitre is a mitre which is beveled at the distance /// determined by the mitre ratio limit. /// </summary> /// <param name="offset0">The first offset segment</param> /// <param name="offset1">The second offset segment</param> /// <param name="distance">The offset distance</param> /// <param name="mitreLimit">The mitre limit ratio</param> private void AddLimitedMitreJoin( LineSegment offset0, LineSegment offset1, double distance, double mitreLimit) { var basePt = _seg0.P1; var ang0 = AngleUtility.Angle(basePt, _seg0.P0); //var ang1 = AngleUtility.Angle(basePt, _seg1.P1); // oriented angle between segments var angDiff = AngleUtility.AngleBetweenOriented(_seg0.P0, basePt, _seg1.P1); // half of the interior angle var angDiffHalf = angDiff / 2; // angle for bisector of the interior angle between the segments var midAng = AngleUtility.Normalize(ang0 + angDiffHalf); // rotating this by PI gives the bisector of the reflex angle var mitreMidAng = AngleUtility.Normalize(midAng + Math.PI); // the miterLimit determines the distance to the mitre bevel var mitreDist = mitreLimit * distance; // the bevel delta is the difference between the buffer distance // and half of the length of the bevel segment var bevelDelta = mitreDist * Math.Abs(Math.Sin(angDiffHalf)); var bevelHalfLen = distance - bevelDelta; // compute the midpoint of the bevel segment var bevelMidX = basePt.X + mitreDist * Math.Cos(mitreMidAng); var bevelMidY = basePt.Y + mitreDist * Math.Sin(mitreMidAng); var bevelMidPt = new Coordinate(bevelMidX, bevelMidY); // compute the mitre midline segment from the corner point to the bevel segment midpoint var mitreMidLine = new LineSegment(basePt, bevelMidPt); // finally the bevel segment endpoints are computed as offsets from // the mitre midline var bevelEndLeft = mitreMidLine.PointAlongOffset(1.0, bevelHalfLen); var bevelEndRight = mitreMidLine.PointAlongOffset(1.0, -bevelHalfLen); if (_side == Positions.Left) { _segList.AddPt(bevelEndLeft); _segList.AddPt(bevelEndRight); } else { _segList.AddPt(bevelEndRight); _segList.AddPt(bevelEndLeft); } }
/** * * * @param offset0 * @param offset1 */ /// <summary> /// Adds a bevel join connecting the two offset segments /// around a reflex corner. /// </summary> /// <param name="offset0">The first offset segment</param> /// <param name="offset1">The second offset segment</param> private void AddBevelJoin( LineSegment offset0, LineSegment offset1) { _segList.AddPt(offset0.P1); _segList.AddPt(offset1.P0); }
private static bool IsSnapped(Coordinate v, Coordinate p0, Coordinate p1) { if (v.Equals2D(p0)) return true; if (v.Equals2D(p1)) return true; var seg = new LineSegment(p0, p1); var dist = seg.Distance(v); if (dist < SnapTolerance / 2.05) return false; return true; }
private void CheckNodePosition(LineSegment seg, Coordinate p0, Coordinate p1, int expectedPositionValue) { Octants octant = Octant.GetOctant(seg.P0, seg.P1); int posValue = SegmentPointComparator.Compare(octant, p0, p1); Console.WriteLine(octant + " " + p0 + " " + p1 + " " + posValue); Assert.IsTrue(posValue == expectedPositionValue); }