/// <summary> /// Implements the total order relation. /// The angle of edge a is greater than the angle of edge b, /// where the angle of an edge is the angle made by /// the first segment of the edge with the positive x-axis. /// When applied to a list of edges originating at the same point, /// this produces a CCW ordering of the edges around the point. /// Using the obvious algorithm of computing the angle is not robust, /// since the angle calculation is susceptible to roundoff error. /// </summary> /// <remarks> /// A robust algorithm is: /// 1. compare the quadrants the edge vectors lie in. /// If the quadrants are different, /// it is trivial to determine which edge has a greater angle. /// 2. If the vectors lie in the same quadrant, the /// <see cref="CGAlgorithms.ComputeOrientation"/> function /// can be used to determine the relative orientation of the vectors. /// </remarks> public int CompareAngularDirection(HalfEdge e) { double dx = DeltaX; double dy = DeltaY; double dx2 = e.DeltaX; double dy2 = e.DeltaY; // same vector if (dx == dx2 && dy == dy2) { return(0); } double quadrant = QuadrantOp.Quadrant(dx, dy); double quadrant2 = QuadrantOp.Quadrant(dx2, dy2); // if the vectors are in different quadrants, determining the ordering is trivial if (quadrant > quadrant2) { return(1); } if (quadrant < quadrant2) { return(-1); } // vectors are in the same quadrant // Check relative orientation of direction vectors // this is > e if it is CCW of e return(CGAlgorithms.ComputeOrientation(e.Orig, e.Dest, Dest)); }
/// <summary> /// Finds the index of the last point in a monotone chain /// starting at a given point. /// Any repeated points (0-length segments) will be included /// in the monotone chain returned. /// </summary> /// <param name="pts">The coordinates</param> /// <param name="start">The start index</param> /// <returns> /// The index of the last point in the monotone chain starting at <c>start</c>. /// </returns> private static int FindChainEnd(Coordinate[] pts, int start) { int safeStart = start; // skip any zero-length segments at the start of the sequence // (since they cannot be used to establish a quadrant) while (safeStart < pts.Length - 1 && pts[safeStart].Equals2D(pts[safeStart + 1])) { safeStart++; } // check if there are NO non-zero-length segments if (safeStart >= pts.Length - 1) { return(pts.Length - 1); } // determine overall quadrant for chain (which is the starting quadrant) int chainQuad = QuadrantOp.Quadrant(pts[safeStart], pts[safeStart + 1]); int last = start + 1; while (last < pts.Length) { // skip zero-length segments, but include them in the chain if (!pts[last - 1].Equals2D(pts[last])) { // compute quadrant for next possible segment in chain int quad = QuadrantOp.Quadrant(pts[last - 1], pts[last]); if (quad != chainQuad) { break; } } last++; } return(last - 1); }
/// <summary> /// Constructs a DirectedEdge connecting the <c>from</c> node to the /// <c>to</c> node. /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="directionPt"> /// Specifies this DirectedEdge's direction (given by an imaginary /// line from the <c>from</c> node to <c>directionPt</c>). /// </param> /// <param name="edgeDirection"> /// Whether this DirectedEdge's direction is the same as or /// opposite to that of the parent Edge (if any). /// </param> public DirectedEdge(Node from, Node to, Coordinate directionPt, bool edgeDirection) { this.from = from; this.to = to; this.EdgeDirection = edgeDirection; p0 = from.Coordinate; p1 = directionPt; double dx = p1.X - p0.X; double dy = p1.Y - p0.Y; _quadrant = QuadrantOp.Quadrant(dx, dy); _angle = Math.Atan2(dy, dx); }
private DirectedEdge _sym; // optional #endregion /// <summary> /// Constructs a DirectedEdge connecting the <c>from</c> node to the /// <c>to</c> node. /// </summary> /// <param name="inFrom"></param> /// <param name="inTo"></param> /// <param name="directionPt"> /// Specifies this DirectedEdge's direction (given by an imaginary /// line from the <c>from</c> node to <c>directionPt</c>). /// </param> /// <param name="inEdgeDirection"> /// Whether this DirectedEdge's direction is the same as or /// opposite to that of the parent Edge (if any). /// </param> public DirectedEdge(Node inFrom, Node inTo, Coordinate directionPt, bool inEdgeDirection) { _from = inFrom; _to = inTo; _edgeDirection = inEdgeDirection; _p0 = _from.Coordinate; _p1 = directionPt; double dx = _p1.X - _p0.X; double dy = _p1.Y - _p0.Y; _quadrant = QuadrantOp.Quadrant(dx, dy); _angle = Math.Atan2(dy, dx); }
/// <returns> /// The index of the last point in the monotone chain. /// </returns> private static int FindChainEnd(IList <Coordinate> pts, int start) { // determine quadrant for chain int chainQuad = QuadrantOp.Quadrant(pts[start], pts[start + 1]); int last = start + 1; while (last < pts.Count) { // compute quadrant for next possible segment in chain int quad = QuadrantOp.Quadrant(pts[last - 1], pts[last]); if (quad != chainQuad) { break; } last++; } return(last - 1); }