예제 #1
0
        /// <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;
            }
        }
예제 #2
0
 /// <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));
 }
예제 #3
0
        /// <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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
 /// <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));
 }
예제 #7
0
        /// <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);
                    }
                }
            }
        }