/// <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; var orient = Orientation.Index(o, p, q); if (orient == OrientationIndex.CounterClockwise) { return(1); } if (orient == OrientationIndex.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> * /// * /// </summary> * /// <param name="ps"></param> * /// <returns></returns> * private Stack<Coordinate> ReverseStack(Stack<Coordinate> ps) * { * // Do a manual reverse of the stack * int size = ps.Count; * var tempArray = new Coordinate[size]; * for (int i = 0; i < size; i++) * tempArray[i] = ps.Pop(); * var returnStack = new Stack<Coordinate>(size); * foreach (Coordinate obj in tempArray) * returnStack.Push(obj); * return returnStack; * } */ /// <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 (Orientation.Index(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="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 ((Orientation.Index(p1, p2, p) == OrientationIndex.Collinear) && (Orientation.Index(p2, p1, p) == OrientationIndex.Collinear)) { IsProper = true; if (p.Equals(p1) || p.Equals(p2)) { IsProper = false; } Result = PointIntersection; return; } } Result = NoIntersection; }
public static int OrientationIndex(Coordinate p1, Coordinate p2, Coordinate q) { /** * MD - 9 Aug 2010 * It seems that the basic algorithm is slightly orientation dependent, * when computing the orientation of a point very close to a line. * This is possibly due to the arithmetic in the translation to the origin. * * For instance, the following situation produces identical results * in spite of the inverse orientation of the line segment: * * Coordinate p0 = new Coordinate(219.3649559090992, 140.84159161824724); * Coordinate p1 = new Coordinate(168.9018919682399, -5.713787599646864); * * Coordinate p = new Coordinate(186.80814046338352, 46.28973405831556); * int orient = orientationIndex(p0, p1, p); * int orientInv = orientationIndex(p1, p0, p); * * A way to force consistent results is to normalize the orientation of the vector * using the following code. * However, this may make the results of orientationIndex inconsistent * through the triangle of points, so it's not clear this is * an appropriate patch. * */ return((int)Orientation.Index(p1, p2, q)); /* * //Testing only * return ShewchuksDeterminant.OrientationIndex(p1, p2, q); */ /* * //previous implementation - not quite fully robust * return RobustDeterminant.OrientationIndex(p1, p2, q); */ }
/// <summary> /// /// </summary> /// <param name="c"></param> /// <returns></returns> private static Stack <Coordinate> GrahamScan(Coordinate[] c) { var 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++) { var p = ps.Pop(); // check for empty stack to guard against robustness problems while ( ps.Count > 0 /*(IsEmpty Hack)*/ && Orientation.Index(ps.Peek(), p, c[i]) > 0) { p = ps.Pop(); } ps.Push(p); ps.Push(c[i]); } ps.Push(c[0]); return(ps); }
public static int ComputeOrientation(Coordinate p1, Coordinate p2, Coordinate q) { return((int)Orientation.Index(p1, p2, q)); }
///<summary> /// Counts a segment ///</summary> /// <param name="p1">An endpoint of the segment</param> /// <param name="p2">Another endpoint of the segment</param> public void CountSegment(Coordinate p1, Coordinate p2) { /* * For each segment, check if it crosses * a horizontal ray running from the test point in the positive x direction. */ // check if the segment is strictly to the left of the test point if (p1.X < _p.X && p2.X < _p.X) { return; } // check if the point is equal to the current ring vertex if (_p.X == p2.X && _p.Y == p2.Y) { _isPointOnSegment = true; return; } /* * For horizontal segments, check if the point is on the segment. * Otherwise, horizontal segments are not counted. */ if (p1.Y == _p.Y && p2.Y == _p.Y) { double minx = p1.X; double maxx = p2.X; if (minx > maxx) { minx = p2.X; maxx = p1.X; } if (_p.X >= minx && _p.X <= maxx) { _isPointOnSegment = true; } return; } /* * Evaluate all non-horizontal segments which cross a horizontal ray to the * right of the test pt. To avoid double-counting shared vertices, we use the * convention that * <ul> * <li>an upward edge includes its starting endpoint, and excludes its * final endpoint * <li>a downward edge excludes its starting endpoint, and includes its * final endpoint * </ul> */ if (((p1.Y > _p.Y) && (p2.Y <= _p.Y)) || ((p2.Y > _p.Y) && (p1.Y <= _p.Y))) { var orient = Orientation.Index(p1, p2, _p); if (orient == OrientationIndex.Collinear) { _isPointOnSegment = true; return; } // Re-orient the result if needed to ensure effective segment direction is upwards if (p2.Y < p1.Y) { orient = Orientation.ReOrient(orient); } // The upward segment crosses the ray if the test point lies to the left (CCW) of the segment. if (orient == OrientationIndex.Left) { _crossingCount++; } } }
public override int 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(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 var Pq1 = Orientation.Index(p1, p2, q1); var Pq2 = Orientation.Index(p1, p2, q2); if ((Pq1 > 0 && Pq2 > 0) || (Pq1 < 0 && Pq2 < 0)) { return(NoIntersection); } var Qp1 = Orientation.Index(q1, q2, p1); var Qp2 = Orientation.Index(q1, q2, p2); if ((Qp1 > 0 && Qp2 > 0) || (Qp1 < 0 && Qp2 < 0)) { return(NoIntersection); } var collinear = Pq1 == 0 && Pq2 == 0 && Qp1 == 0 && Qp2 == 0; if (collinear) { return(ComputeCollinearIntersection(p1, p2, q1, q2)); } /* * 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) { IsProper = false; /* * Check for two equal endpoints. * This is done explicitly rather than by the orientation tests * below in order to improve robustness. * * [An example where the orientation tests fail to be consistent is * the following (where the true intersection is at the shared endpoint * POINT (19.850257749638203 46.29709338043669) * * LINESTRING ( 19.850257749638203 46.29709338043669, 20.31970698357233 46.76654261437082 ) * and * LINESTRING ( -48.51001596420236 -22.063180333403878, 19.850257749638203 46.29709338043669 ) * * which used to produce the INCORRECT result: (20.31970698357233, 46.76654261437082, NaN) * */ if (p1.Equals2D(q1) || p1.Equals2D(q2)) { IntersectionPoint[0] = p1; } else if (p2.Equals2D(q1) || p2.Equals2D(q2)) { IntersectionPoint[0] = p2; } else if (Pq1 == 0) { IntersectionPoint[0] = new Coordinate(q1); } else if (Pq2 == 0) { IntersectionPoint[0] = new Coordinate(q2); } else if (Qp1 == 0) { IntersectionPoint[0] = new Coordinate(p1); } else if (Qp2 == 0) { IntersectionPoint[0] = new Coordinate(p2); } } else { IsProper = true; IntersectionPoint[0] = Intersection(p1, p2, q1, q2); } return(PointIntersection); }