/// <summary> /// /// </summary> private void FindRightmostEdgeAtVertex() { /* * The rightmost point is an interior vertex, so it has a segment on either side of it. * If these segments are both above or below the rightmost point, we need to * determine their relative orientation to decide which is rightmost. */ IList <Coordinate> pts = _minDe.Edge.Coordinates; Assert.IsTrue(_minIndex > 0 && _minIndex < pts.Count, "rightmost point expected to be interior vertex of edge"); Coordinate pPrev = pts[_minIndex - 1]; Coordinate pNext = pts[_minIndex + 1]; int orientation = CgAlgorithms.ComputeOrientation(_minCoord, pNext, pPrev); bool usePrev = false; // both segments are below min point if (pPrev.Y < _minCoord.Y && pNext.Y < _minCoord.Y && orientation == CgAlgorithms.COUNTER_CLOCKWISE) { usePrev = true; } else if (pPrev.Y > _minCoord.Y && pNext.Y > _minCoord.Y && orientation == CgAlgorithms.CLOCKWISE) { usePrev = true; } // if both segments are on the same side, do nothing - either is safe // to select as a rightmost segment if (usePrev) { _minIndex = _minIndex - 1; } }
/// <summary> /// The coordinate pairs match if they define line segments lying in the same direction. /// E.g. the segments are parallel and in the same quadrant /// (as opposed to parallel and opposite!). /// </summary> /// <param name="p0"></param> /// <param name="p1"></param> /// <param name="ep0"></param> /// <param name="ep1"></param> private static bool MatchInSameDirection(Coordinate p0, Coordinate p1, Coordinate ep0, Coordinate ep1) { if (!p0.Equals(ep0)) { return(false); } return(CgAlgorithms.ComputeOrientation(p0, p1, ep1) == CgAlgorithms.COLLINEAR && QuadrantOp.Quadrant(p0, p1) == QuadrantOp.Quadrant(ep0, ep1)); }
/// <summary> /// Finds all non-horizontal segments intersecting the stabbing line /// in the input dirEdge. /// The stabbing line is the ray to the right of stabbingRayLeftPt. /// </summary> /// <param name="stabbingRayLeftPt">The left-hand origin of the stabbing line.</param> /// <param name="dirEdge"></param> /// <param name="stabbedSegments">The current list of DepthSegments intersecting the stabbing line.</param> private void FindStabbedSegments(Coordinate stabbingRayLeftPt, DirectedEdge dirEdge, IList stabbedSegments) { IList <Coordinate> pts = dirEdge.Edge.Coordinates; for (int i = 0; i < pts.Count - 1; i++) { _seg.P0 = pts[i]; _seg.P1 = pts[i + 1]; // ensure segment always points upwards if (_seg.P0.Y > _seg.P1.Y) { _seg.Reverse(); } // skip segment if it is left of the stabbing line double maxx = Math.Max(_seg.P0.X, _seg.P1.X); if (maxx < stabbingRayLeftPt.X) { continue; } // skip horizontal segments (there will be a non-horizontal one carrying the same depth info if (_seg.IsHorizontal) { continue; } // skip if segment is above or below stabbing line if (stabbingRayLeftPt.Y < _seg.P0.Y || stabbingRayLeftPt.Y > _seg.P1.Y) { continue; } // skip if stabbing ray is right of the segment if (CgAlgorithms.ComputeOrientation(_seg.P0, _seg.P1, stabbingRayLeftPt) == CgAlgorithms.RIGHT) { continue; } // stabbing line cuts this segment, so record it int depth = dirEdge.GetDepth(PositionType.Left); // if segment direction was flipped, use RHS depth instead if (!_seg.P0.Equals(pts[i])) { depth = dirEdge.GetDepth(PositionType.Right); } DepthSegment ds = new DepthSegment(_seg, depth); stabbedSegments.Add(ds); } }
private static bool IsAllCW(IPolygon poly) { IList <Coordinate> shell = poly.Shell.Coordinates; for (int i = 0, c = shell.Count - 3; i < c; i++) { if (CgAlgorithms.ComputeOrientation(shell[i], shell[i + 1], shell[i + 2]) == 1) { return(false); } } return(true); }
/// <summary> /// Returns 1 if this DirectedEdge has a greater angle with the /// positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. /// Using the obvious algorithm of simply computing the angle is not robust, /// since the angle calculation is susceptible to roundoff. A robust algorithm /// is: /// first compare the quadrants. If the quadrants are different, it it /// trivial to determine which vector is "greater". /// if the vectors lie in the same quadrant, the robust /// <c>RobustCgAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate)</c> /// function can be used to decide the relative orientation of the vectors. /// </summary> /// <param name="e"></param> /// <returns></returns> public virtual int CompareDirection(DirectedEdge e) { // if the rays are in different quadrants, determining the ordering is trivial if (_quadrant > e.Quadrant) { return(1); } if (_quadrant < e.Quadrant) { return(-1); } // vectors are in the same quadrant - check relative orientation of direction vectors // this is > e if it is CCW of e int i = CgAlgorithms.ComputeOrientation(e.StartPoint, e.EndPoint, _p1); return(i); }
/// <summary> /// Implements the total order relation: /// a has a greater angle with the positive x-axis than b. /// Using the obvious algorithm of simply computing the angle is not robust, /// since the angle calculation is obviously susceptible to roundoff. /// A robust algorithm is: /// - first compare the quadrant. If the quadrants /// are different, it it trivial to determine which vector is "greater". /// - if the vectors lie in the same quadrant, the computeOrientation function /// can be used to decide the relative orientation of the vectors. /// </summary> /// <param name="e"></param> public virtual int CompareDirection(EdgeEnd e) { if (_dx == e._dx && _dy == e._dy) { return(0); } // if the rays are in different quadrants, determining the ordering is trivial if (_quadrant > e._quadrant) { return(1); } if (_quadrant < e._quadrant) { 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._p0, e._p1, _p1)); }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="addStartPoint"></param> private void AddNextSegment(Coordinate p, bool addStartPoint) { // s0-s1-s2 are the coordinates of the previous segment and the current one _s0 = _s1; _s1 = _s2; _s2 = p; _seg0.SetCoordinates(_s0, _s1); ComputeOffsetSegment(_seg0, _side, _distance, _offset0); _seg1.SetCoordinates(_s1, _s2); ComputeOffsetSegment(_seg1, _side, _distance, _offset1); // do nothing if points are equal if (_s1.Equals(_s2)) { return; } int orientation = CgAlgorithms.ComputeOrientation(_s0, _s1, _s2); bool outsideTurn = (orientation == CgAlgorithms.CLOCKWISE && _side == PositionType.Left) || (orientation == CgAlgorithms.COUNTER_CLOCKWISE && _side == PositionType.Right); if (orientation == 0) { // lines are collinear _li.ComputeIntersection(_s0, _s1, _s1, _s2); int numInt = _li.IntersectionNum; /* * if numInt is < 2, the lines are parallel and in the same direction. * In this case the point can be ignored, since the offset lines will also be * parallel. */ if (numInt >= 2) { /* * segments are collinear but reversing. Have to add an "end-cap" fillet * all the way around to other direction * This case should ONLY happen for LineStrings, so the orientation is always CW. * (Polygons can never have two consecutive segments which are parallel but reversed, * because that would be a self intersection. */ AddFillet(_s1, _offset0.P1, _offset1.P0, CgAlgorithms.CLOCKWISE, _distance); } } else if (outsideTurn) { // add a fillet to connect the endpoints of the offset segments if (addStartPoint) { AddPt(_offset0.P1); } AddFillet(_s1, _offset0.P1, _offset1.P0, orientation, _distance); AddPt(_offset1.P0); } else { // inside turn /* * add intersection point of offset segments (if any) */ _li.ComputeIntersection(_offset0.P0, _offset0.P1, _offset1.P0, _offset1.P1); if (_li.HasIntersection) { AddPt(_li.GetIntersection(0)); } else { /* * If no intersection, it means the angle is so small and/or the offset so large * that the offsets segments don't intersect. * In this case we must add a offset joining curve to make sure the buffer line * is continuous and tracks the buffer correctly around the corner. * Notice that the joining curve won't appear in the final buffer. * * The intersection test above is vulnerable to robustness errors; * i.e. it may be that the offsets should intersect very close to their * endpoints, but don't due to rounding. To handle this situation * appropriately, we use the following test: * If the offset points are very close, don't add a joining curve * but simply use one of the offset points */ if (new Coordinate(_offset0.P1).Distance(_offset1.P0) < _distance / 1000.0) { AddPt(_offset0.P1); } else { // add endpoint of this segment offset AddPt(_offset0.P1); // <FIX> MD - add in centre point of corner, to make sure offset closer lines have correct topology AddPt(_s1); AddPt(_offset1.P0); } } } }