Exemple #1
0
 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;
 }
Exemple #2
0
 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;
 }
Exemple #3
0
 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;
 }
Exemple #4
0
 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);
            }
        }
Exemple #7
0
        /// <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)));
        }