/// <summary>
        /// Adds an offset curve for a polygon ring.
        /// The side and left and right topological location arguments
        /// assume that the ring is oriented CW.
        /// If the ring is in the opposite orientation,
        /// the left and right locations must be interchanged and the side flipped.
        /// </summary>
        /// <param name="coord">The coordinates of the ring (must not contain repeated points).</param>
        /// <param name="offsetDistance">The distance at which to create the buffer.</param>
        /// <param name="side">The side of the ring on which to construct the buffer line.</param>
        /// <param name="cwLeftLoc">The location on the L side of the ring (if it is CW).</param>
        /// <param name="cwRightLoc">The location on the R side of the ring (if it is CW).</param>
        private void AddRingSide(Coordinate[] coord, double offsetDistance,
                                 Position side, Location cwLeftLoc, Location cwRightLoc)
        {
            // don't bother adding ring if it is "flat" and will disappear in the output
            if (offsetDistance == 0.0 && coord.Length < LinearRing.MinimumValidSize)
            {
                return;
            }

            var leftLoc  = cwLeftLoc;
            var rightLoc = cwRightLoc;

            /*
             * Use area-based orientation test,
             * to ensure that for invalid rings the largest enclosed area
             * is used to determine orientation.
             * This produces a more sensible result especially when
             * used for validifying polygonal geometry via buffer-by-zero.
             * For buffering use, the lower robustness of ccw-by-area
             * doesn't matter, since very narrow or flat rings
             * produce an acceptable offset curve for either orientation.
             */
            if (coord.Length >= LinearRing.MinimumValidSize &&
                Orientation.IsCCWArea(coord))
            {
                leftLoc  = cwRightLoc;
                rightLoc = cwLeftLoc;
                side     = side.Opposite;
            }
            var curve = _curveBuilder.GetRingCurve(coord, side, offsetDistance);

            AddCurve(curve, leftLoc, rightLoc);
        }
 private void InitSideSegments(Coordinate s1, Coordinate s2, Position side)
 {
     _s1   = s1;
     _s2   = s2;
     _side = side;
     _seg1.SetCoordinates(s1, s2);
     ComputeOffsetSegment(_seg1, side, _distance, _offset1);
 }
        /// <summary>
        /// Compute an offset segment for an input segment on a given side and at a given distance.
        /// The offset points are computed in full double precision, for accuracy.
        /// </summary>
        /// <param name="seg">The segment to offset</param>
        /// <param name="side">The side of the segment (<see cref="Positions"/>) the offset lies on</param>
        /// <param name="distance">The offset distance</param>
        /// <param name="offset">The points computed for the offset segment</param>
        private static void ComputeOffsetSegment(LineSegment seg, Position side, double distance, LineSegment offset)
        {
            int    sideSign = side == Position.Left ? 1 : -1;
            double dx       = seg.P1.X - seg.P0.X;
            double dy       = seg.P1.Y - seg.P0.Y;
            double len      = Math.Sqrt(dx * dx + dy * dy);
            // u is the vector that is the length of the offset, in the direction of the segment
            double ux = sideSign * distance * dx / len;
            double uy = sideSign * distance * dy / len;

            offset.P0.X = seg.P0.X - uy;
            offset.P0.Y = seg.P0.Y + ux;
            offset.P1.X = seg.P1.X - uy;
            offset.P1.Y = seg.P1.Y + ux;
        }
        /// <summary>
        /// This method handles the degenerate cases of single points and lines,
        /// as well as rings.
        /// </summary>
        /// <returns>A Coordinate array representing the curve<br/>
        /// or <c>null</c> if the curve is empty</returns>
        public Coordinate[] GetRingCurve(Coordinate[] inputPts, Position side, double distance)
        {
            _distance = distance;
            if (inputPts.Length <= 2)
            {
                return(GetLineCurve(inputPts, distance));
            }

            // optimize creating ring for for zero distance
            if (distance == 0.0)
            {
                return(CopyCoordinates(inputPts));
            }
            var segGen = GetSegmentGenerator(distance);

            ComputeRingBufferCurve(inputPts, side, segGen);
            return(segGen.GetCoordinates());
        }
Пример #5
0
 /// <summary>
 /// To compute the summary label for a side, the algorithm is:
 /// FOR all edges
 /// IF any edge's location is Interior for the side, side location = Interior
 /// ELSE IF there is at least one Exterior attribute, side location = Exterior
 /// ELSE  side location = Null
 /// Note that it is possible for two sides to have apparently contradictory information
 /// i.e. one edge side may indicate that it is in the interior of a point, while
 /// another edge side may indicate the exterior of the same point.  This is
 /// not an incompatibility - GeometryCollections may contain two Polygons that touch
 /// along an edge.  This is the reason for Interior-primacy rule above - it
 /// results in the summary label having the Geometry interior on both sides.
 /// </summary>
 /// <param name="geomIndex"></param>
 /// <param name="side"></param>
 private void ComputeLabelSide(int geomIndex, Position side)
 {
     foreach (var e in _edgeEnds)
     {
         if (e.Label.IsArea())
         {
             var loc = e.Label.GetLocation(geomIndex, side);
             if (loc == Location.Interior)
             {
                 Label.SetLocation(geomIndex, side, Location.Interior);
                 return;
             }
             if (loc == Location.Exterior)
             {
                 Label.SetLocation(geomIndex, side, Location.Exterior);
             }
         }
     }
 }
        /// <summary>
        /// This method handles the degenerate cases of single points and lines, as well as rings.
        /// </summary>
        /// <returns>a List of Coordinate[]</returns>
        public IList <Coordinate[]> GetRingCurve(Coordinate[] inputPts, Position side, double distance)
        {
            var lineList = new List <Coordinate[]>();

            Init(distance);
            if (inputPts.Length <= 2)
            {
                return(GetLineCurve(inputPts, distance));
            }

            // optimize creating ring for for zero distance
            if (distance == 0.0)
            {
                lineList.Add(CopyCoordinates(inputPts));
                return(lineList);
            }
            ComputeRingBufferCurve(inputPts, side);
            lineList.Add(_vertexList.Coordinates);
            return(lineList);
        }
        private void ComputeRingBufferCurve(Coordinate[] inputPts, Position side)
        {
            // simplify input line to improve performance
            double distTol = SimplifyTolerance(_distance);

            // ensure that correct side is simplified
            if (side == Position.Right)
            {
                distTol = -distTol;
            }
            var simp = BufferInputLineSimplifier.Simplify(inputPts, distTol);
            // Coordinate[] simp = inputPts;

            int n = simp.Length - 1;

            InitSideSegments(simp[n - 1], simp[0], side);
            for (int i = 1; i <= n; i++)
            {
                bool addStartPoint = i != 1;
                AddNextSegment(simp[i], addStartPoint);
            }
            _vertexList.CloseRing();
        }
        private void ComputeRingBufferCurve(Coordinate[] inputPts, Position side, OffsetSegmentGenerator segGen)
        {
            // simplify input line to improve performance
            double distTol = SimplifyTolerance(_distance);

            // ensure that correct side is simplified
            if (side == Position.Right)
            {
                distTol = -distTol;
            }
            var simp = BufferInputLineSimplifier.Simplify(inputPts, distTol);
            // MD - used for testing only (to eliminate simplification)
            // Coordinate[] simp = inputPts;

            int n = simp.Length - 1;

            segGen.InitSideSegments(simp[n - 1], simp[0], side);
            for (int i = 1; i <= n; i++)
            {
                bool addStartPoint = i != 1;
                segGen.AddNextSegment(simp[i], addStartPoint);
            }
            segGen.CloseRing();
        }