internal Ray2(Point2 <T> start, Point2 <T> orientationPoint) { if (start == null || orientationPoint == null) { throw new ArgumentNullException(); } if (start.Equals(orientationPoint)) { throw new DegenerateCaseException(); } this.Start = start; this.OrientationPoint = orientationPoint; }
internal LineSegment2(Point2 <T> start, Point2 <T> end) { if (start == null || end == null) { throw new ArgumentNullException(); } if (start.Equals(end)) { throw new DegenerateCaseException(); } this.Start = start; this.End = end; }
internal Line2(Point2 <T> anchor, Point2 <T> orientationPoint) { if (anchor == null || orientationPoint == null) { MethodContract.NotNull(anchor, nameof(anchor)); MethodContract.NotNull(orientationPoint, nameof(orientationPoint)); } if (anchor.Equals(orientationPoint)) { throw new DegenerateCaseException(); } this.Anchor = anchor; this.OrientationPoint = orientationPoint; }
public bool HasCoincidentPoints() {//n^2, ouch for (int i = 1; i < this.Points.Length; i++) { Point2 <T> cur = this.Points[i]; for (int j = 0; j < i; j++) { if (cur.Equals(this.Points[j])) { return(true); } } } return(false); }
public static double Distance(Point2 <double> p1, Point2 <double> p2, Point2 <double> q) { if (p1.Equals(p2)) { return(PointUtilsDouble.Distance(p1, q)); } double r = ((q.X - p1.X) * (p2.X - p1.X) + (q.Y - p1.Y) * (p2.Y - p1.Y)) / ((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y)); if (r <= 0.0d) { return(PointUtilsDouble.Distance(q, p1)); } if (r >= 1.0d) { return(PointUtilsDouble.Distance(q, p2)); } double s = ((p1.Y - q.Y) * (p2.X - p1.X) - (p1.X - q.X) * (p2.Y - p1.Y)) / ((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y)); return(Math.Abs(s) * Math.Sqrt(((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y)))); }
public static Point2 <double> NearestPoint(Point2 <double> p0, Point2 <double> p1, Point2 <double> q) { if (p0.Equals(p1)) { return(p0); } double s1 = (p1.Y - p0.Y) * (q.Y - p0.Y) + (p1.X - p0.X) * (q.X - p0.X); double s2 = (p1.Y - p0.Y) * (q.Y - p1.Y) + (p1.X - p0.X) * (q.X - p1.X); if (s1 * s2 <= 0) { double lam = (p0.Y - p1.Y) * (p0.Y - p1.Y) + (p0.X - p1.X) * (p0.X - p1.X); //dotproduct of p0-p1 lam = ((q.Y - p0.Y) * (p0.Y - p1.Y) + (q.X - p0.X) * (p0.X - p1.X)) / lam; return(q.Factory.ConstructPoint(p0.X + lam * (p0.X - p1.X), p0.Y + lam * (p0.Y - p1.Y))); } else { return((s1 > 0) ? p1 : p0); } }
/// <summary> /// Computes whether a ring defined by an array of {@link Coordinate}s is oriented counter-clockwise. /// <ul><li>The list of points is assumed to have the first and last points equal. /// <li>This will handle coordinate lists which contain repeated points.</ul> /// This algorithm is <b>only</b> guaranteed to work with valid rings. /// If the ring is invalid (e.g. self-crosses or touches), the computed result may not be correct. /// </summary> /// <param name="ring"></param> /// <returns></returns> public static bool IsCCW(Point2 <double>[] ring) { if (ring.Length < 3) { return(false); } int nPts = ring.Length - 1; // find highest point Point2 <double> hiPt = ring[0]; int hiIndex = 0; for (int i = 1; i < ring.Length; i++) { Point2 <double> p = ring[i]; if (p.Y > hiPt.Y) { hiPt = p; hiIndex = i; } } // find distinct point before highest point int iPrev = hiIndex; do { iPrev = iPrev - 1; if (iPrev < 0) { iPrev = nPts; } } while (ring[iPrev].Equals(hiPt) && iPrev != hiIndex); // find distinct point after highest point int iNext = hiIndex; do { iNext = (iNext + 1) % nPts; } while (ring[iNext].Equals(hiPt) && iNext != hiIndex); Point2 <double> prev = ring[iPrev]; Point2 <double> next = ring[iNext]; // This check catches cases where the ring contains an A-B-A configuration of points. // This can happen if the ring does not contain 3 distinct points (including the case where the input array has fewer than 4 elements), or it contains coincident line segments. if (prev.Equals(hiPt) || next.Equals(hiPt) || prev.Equals(next)) { return(false); } int disc = Coordinate2Utils.OrientationIndex(prev.X, prev.Y, hiPt.X, hiPt.Y, next.X, next.Y); // If disc is exactly 0, lines are collinear. There are two possible cases: // (1) the lines lie along the x axis in opposite directions (is handled by checking if next is left of prev ==> CCW) // (2) the lines lie on top of one another (will never happen if the ring is valid, so don't check for it) bool isCCW = false; if (disc == 0) //poly is CCW if prev x is right of next x { isCCW = (prev.X > next.X); } else // if area is positive, points are ordered CCW { isCCW = (disc > 0); } return(isCCW); }
public static LineSegment2IntersectionResult <double> ComputeIntersection(Point2 <double> p1, Point2 <double> p2, Point2 <double> q1, Point2 <double> q2) { if (p1 == null || p2 == null || q1 == null || q2 == null) { return(null); } //quick rejection if (!Coordinate2Utils.EnvelopesIntersect(p1, p2, q1, q2)) { return(new LineSegment2IntersectionResult <double>()); } // for each endpoint, compute which side of the other segment it lies // if both endpoints lie on the same side of the other segment, the segments do not intersect int Pq1 = Coordinate2Utils.OrientationIndex(p1, p2, q1); int Pq2 = Coordinate2Utils.OrientationIndex(p1, p2, q2); if ((Pq1 > 0 && Pq2 > 0) || (Pq1 < 0 && Pq2 < 0)) { return(new LineSegment2IntersectionResult <double>()); } int Qp1 = Coordinate2Utils.OrientationIndex(q1, q2, p1); int Qp2 = Coordinate2Utils.OrientationIndex(q1, q2, p2); if ((Qp1 > 0 && Qp2 > 0) || (Qp1 < 0 && Qp2 < 0)) { return(new LineSegment2IntersectionResult <double>()); } //end quick rejection if (Pq1 == 0 && Pq2 == 0 && Qp1 == 0 && Qp2 == 0) //collinear intersection { bool p1q1p2 = Coordinate2Utils.PointInEnvelope(p1, p2, q1); bool p1q2p2 = Coordinate2Utils.PointInEnvelope(p1, p2, q2); bool q1p1q2 = Coordinate2Utils.PointInEnvelope(q1, q2, p1); bool q1p2q2 = Coordinate2Utils.PointInEnvelope(q1, q2, p2); if (p1q1p2 && p1q2p2) { return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, q1, q2)); } if (q1p1q2 && q1p2q2) { return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, p1, p2)); } if (p1q1p2 && q1p1q2) { if (q1.Equals(p1) && !p1q2p2 && !q1p2q2) { return(new LineSegment2IntersectionResult <double>(q1)); } return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, q1, p1)); } if (p1q1p2 && q1p2q2) { if (q1.Equals(p2) && !p1q2p2 && !q1p1q2) { return(new LineSegment2IntersectionResult <double>(q1)); } return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, q1, p2)); } if (p1q2p2 && q1p1q2) { if (q2.Equals(p1) && !p1q1p2 && !q1p2q2) { return(new LineSegment2IntersectionResult <double>(q2)); } return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, q2, p1)); } if (p1q2p2 && q1p2q2) { if (q2.Equals(p2) && !p1q1p2 && !q1p1q2) { return(new LineSegment2IntersectionResult <double>(q2)); } return(new LineSegment2IntersectionResult <double>(LineIntersectionType.CollinearIntersection, q2, p2)); } return(new LineSegment2IntersectionResult <double>()); }//end collinear // At this point we know that there is a single intersection point (since the lines are not collinear). // Check if the intersection is an endpoint. If it is, copy the endpoint as the intersection point. Copying the point rather than computing it // ensures the point has the exact value, which is important for robustness. It is sufficient to simply check for an endpoint which is on // the other line, since at this point we know that the inputLines must intersect. if (Pq1 == 0 || Pq2 == 0 || Qp1 == 0 || Qp2 == 0) { // Check for two equal endpoints. This is done explicitly rather than by the orientation tests below in order to improve robustness. if (p1.Equals(q1) || p1.Equals(q2)) { return(new LineSegment2IntersectionResult <double>(p1)); } else if (p2.Equals(q1) || p2.Equals(q2)) { return(new LineSegment2IntersectionResult <double>(p2)); } // Now check to see if any endpoint lies on the interior of the other segment. else if (Pq1 == 0) { return(new LineSegment2IntersectionResult <double>(q1)); } else if (Pq2 == 0) { return(new LineSegment2IntersectionResult <double>(q2)); } else if (Qp1 == 0) { return(new LineSegment2IntersectionResult <double>(p1)); } else if (Qp2 == 0) { return(new LineSegment2IntersectionResult <double>(p2)); } } //end exact at endpoint //intersectWNormalization Coordinate2 <double> n1 = new Coordinate2 <double>(p1); Coordinate2 <double> n2 = new Coordinate2 <double>(p2); Coordinate2 <double> n3 = new Coordinate2 <double>(q1); Coordinate2 <double> n4 = new Coordinate2 <double>(q2); Coordinate2 <double> normPt = new Coordinate2 <double>(); Coordinate2Utils.NormalizeToEnvCentre(n1, n2, n3, n4, normPt); //safeHCoordinateIntersection Coordinate2 <double> intPt = null; // unrolled computation double px = n1.Y - n2.Y; double py = n2.X - n1.X; double pw = n1.X * n2.Y - n2.X * n1.Y; double qx = n3.Y - n4.Y; double qy = n4.X - n3.X; double qw = n3.X * n4.Y - n4.X * n3.Y; double x = py * qw - qy * pw; double y = qx * pw - px * qw; double w = px * qy - qx * py; double xInt = x / w; double yInt = y / w; if (double.IsNaN(xInt) || double.IsNaN(yInt) || double.IsInfinity(xInt) || double.IsInfinity(yInt)) { intPt = MeanNearest(n1, n2, n3, n4); xInt = intPt.X + normPt.X; yInt = intPt.Y + normPt.Y; return(new LineSegment2IntersectionResult <double>(p1.Factory.ConstructPoint(xInt, yInt))); } else { xInt += normPt.X; yInt += normPt.Y; intPt = new Coordinate2 <double>(xInt, yInt); } //End safeHCoordinateIntersection //End intersectWNormalization if (!(Coordinate2Utils.PointInEnvelope(p1, p2, intPt) || Coordinate2Utils.PointInEnvelope(q1, q2, intPt))) { intPt = MeanNearest(p1, p2, q1, q2); } return(new LineSegment2IntersectionResult <double>(p1.Factory.ConstructPoint(intPt.X, intPt.Y))); }