/// <summary> /// /// </summary> /// <param name="o"></param> /// <param name="p"></param> /// <param name="q"></param> /// <returns></returns> private static int PolarCompare(Coordinate o, Coordinate p, Coordinate q) { double dxp = p.X - o.X; double dyp = p.Y - o.Y; double dxq = q.X - o.X; double dyq = q.Y - o.Y; int orient = CgAlgorithms.ComputeOrientation(o, p, q); if (orient == CgAlgorithms.COUNTER_CLOCKWISE) { return(1); } if (orient == CgAlgorithms.CLOCKWISE) { return(-1); } // points are collinear - check distance double op = dxp * dxp + dyp * dyp; double oq = dxq * dxq + dyq * dyq; if (op < oq) { return(-1); } if (op > oq) { return(1); } return(0); }
/// <summary> /// Uses a heuristic to reduce the number of points scanned to compute the hull. /// The heuristic is to find a polygon guaranteed to /// be in (or on) the hull, and eliminate all points inside it. /// A quadrilateral defined by the extremal points /// in the four orthogonal directions /// can be used, but even more inclusive is /// to use an octilateral defined by the points in the 8 cardinal directions. /// Notice that even if the method used to determine the polygon vertices /// is not 100% robust, this does not affect the robustness of the convex hull. /// </summary> /// <param name="pts"></param> /// <returns></returns> private static Coordinate[] Reduce(Coordinate[] pts) { Coordinate[] polyPts = ComputeOctRing(pts); // unable to compute interior polygon for some reason if (polyPts == null) { return(pts); } // add points defining polygon Iesi.Collections.Generic.SortedSet <Coordinate> reducedSet = new Iesi.Collections.Generic.SortedSet <Coordinate>(); for (int i = 0; i < polyPts.Length; i++) { reducedSet.Add(polyPts[i]); } /* * Add all unique points not in the interior poly. * CgAlgorithms.IsPointInRing is not defined for points actually on the ring, * but this doesn't matter since the points of the interior polygon * are forced to be in the reduced set. */ for (int i = 0; i < pts.Length; i++) { if (!CgAlgorithms.IsPointInRing(pts[i], polyPts)) { reducedSet.Add(pts[i]); } } Coordinate[] arr = new Coordinate[reducedSet.Count]; reducedSet.CopyTo(arr, 0); return(arr); }
/// <summary> /// /// </summary> /// <param name="c1"></param> /// <param name="c2"></param> /// <param name="c3"></param> /// <returns> /// Whether the three coordinates are collinear /// and c2 lies between c1 and c3 inclusive. /// </returns> private static bool IsBetween(Coordinate c1, Coordinate c2, Coordinate c3) { if (CgAlgorithms.ComputeOrientation(c1, c2, c3) != 0) { return(false); } if (c1.X != c3.X) { if (c1.X <= c2.X && c2.X <= c3.X) { return(true); } if (c3.X <= c2.X && c2.X <= c1.X) { return(true); } } if (c1.Y != c3.Y) { if (c1.Y <= c2.Y && c2.Y <= c3.Y) { return(true); } if (c3.Y <= c2.Y && c2.Y <= c1.Y) { return(true); } } return(false); }
/// <summary> /// /// </summary> /// <param name="pts"></param> private void AddHole(IList <Coordinate> pts) { bool isPositiveArea = CgAlgorithms.IsCounterClockwise(pts); for (int i = 0; i < pts.Count - 1; i++) { AddTriangle(_basePt, pts[i], pts[i + 1], isPositiveArea); } }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="ring"></param> /// <returns></returns> private static LocationType LocateInPolygonRing(Coordinate p, IBasicGeometry ring) { // can this test be folded into IsPointInRing? if (CgAlgorithms.IsOnLine(p, ring.Coordinates)) { return(LocationType.Boundary); } if (CgAlgorithms.IsPointInRing(p, ring.Coordinates)) { return(LocationType.Interior); } return(LocationType.Exterior); }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="l"></param> /// <returns></returns> private static LocationType LocateInLineString(Coordinate p, ILineString l) { IList <Coordinate> pt = l.Coordinates; if (!l.IsClosed) { if (p.Equals(pt[0]) || p.Equals(pt[pt.Count - 1])) { return(LocationType.Boundary); } } if (CgAlgorithms.IsOnLine(p, pt)) { return(LocationType.Interior); } return(LocationType.Exterior); }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="p1"></param> /// <param name="p2"></param> public override void ComputeIntersection(Coordinate p, Coordinate p1, Coordinate p2) { IsProper = false; // do between check first, since it is faster than the orientation test if (Envelope.Intersects(p1, p2, p)) { if ((CgAlgorithms.OrientationIndex(p1, p2, p) == 0) && (CgAlgorithms.OrientationIndex(p2, p1, p) == 0)) { IsProper = true; if (p.Equals(p1) || p.Equals(p2)) { IsProper = false; } Result = IntersectionType.PointIntersection; return; } } Result = IntersectionType.NoIntersection; }
/// <summary> /// /// </summary> /// <param name="c"></param> /// <returns></returns> private static Stack <Coordinate> GrahamScan(Coordinate[] c) { Stack <Coordinate> ps = new Stack <Coordinate>(c.Length); ps.Push(c[0]); ps.Push(c[1]); ps.Push(c[2]); for (int i = 3; i < c.Length; i++) { Coordinate p = ps.Pop(); while (CgAlgorithms.ComputeOrientation(ps.Peek(), p, c[i]) > 0) { p = ps.Pop(); } ps.Push(p); ps.Push(c[i]); } ps.Push(c[0]); return(ps); }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="poly"></param> /// <returns></returns> public static bool ContainsPointInPolygon(Coordinate p, IPolygon poly) { if (poly.IsEmpty) { return(false); } LinearRing shell = (LinearRing)poly.Shell; if (!CgAlgorithms.IsPointInRing(p, shell.Coordinates)) { return(false); } // now test if the point lies in or on the holes for (int i = 0; i < poly.NumHoles; i++) { LinearRing hole = (LinearRing)poly.GetInteriorRingN(i); if (CgAlgorithms.IsPointInRing(p, hole.Coordinates)) { return(false); } } return(true); }
/// <summary> /// /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="q1"></param> /// <param name="q2"></param> /// <returns></returns> public override IntersectionType ComputeIntersect(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) { IsProper = false; // first try a fast test to see if the envelopes of the lines intersect if (!Envelope.Intersects(p1, p2, q1, q2)) { return(IntersectionType.NoIntersection); } // 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 = CgAlgorithms.OrientationIndex(p1, p2, q1); int pq2 = CgAlgorithms.OrientationIndex(p1, p2, q2); if ((pq1 > 0 && pq2 > 0) || (pq1 < 0 && pq2 < 0)) { return(IntersectionType.NoIntersection); } int qp1 = CgAlgorithms.OrientationIndex(q1, q2, p1); int qp2 = CgAlgorithms.OrientationIndex(q1, q2, p2); if ((qp1 > 0 && qp2 > 0) || (qp1 < 0 && qp2 < 0)) { return(IntersectionType.NoIntersection); } bool collinear = (pq1 == 0 && pq2 == 0 && qp1 == 0 && qp2 == 0); if (collinear) { return(ComputeCollinearIntersection(p1, p2, q1, q2)); } /* * 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) { IsProper = false; if (pq1 == 0) { IntersectionPoints[0] = new Coordinate(q1); } if (pq2 == 0) { IntersectionPoints[0] = new Coordinate(q2); } if (qp1 == 0) { IntersectionPoints[0] = new Coordinate(p1); } if (qp2 == 0) { IntersectionPoints[0] = new Coordinate(p2); } } else { IsProper = true; IntersectionPoints[0] = Intersection(p1, p2, q1, q2); } return(IntersectionType.PointIntersection); }
/// <summary> /// /// </summary> /// <param name="pt"></param> /// <returns></returns> public virtual bool IsInside(Coordinate pt) { return(CgAlgorithms.IsPointInRing(pt, _pts)); }