예제 #1
0
        /// <summary>
        /// Generates a new feature from the buffer of this feature.  The DataRow of
        /// the new feature will be null.
        /// </summary>
        /// <param name="self">This feature</param>
        /// <param name="distance">The double distance</param>
        /// <param name="endCapStyle">The end cap style to use</param>
        /// <returns>An IFeature representing the output from the buffer operation</returns>
        public static IFeature Buffer(this IFeature self, double distance, EndCapStyle endCapStyle)
        {
            IGeometry g = self.Geometry.Buffer(distance, new BufferParameters {
                EndCapStyle = endCapStyle
            });

            return(new Feature(g));
        }
 /// <summary>
 /// Creates a set of parameters with the
 /// given parameter values.
 /// </summary>
 /// <param name="quadrantSegments"> the number of quadrant segments to use</param>
 /// <param name="endCapStyle"> the end cap style to use</param>
 /// <param name="joinStyle"> the join style to use</param>
 /// <param name="mitreLimit"> the mitre limit to use</param>
 public BufferParameters(int quadrantSegments,
                         EndCapStyle endCapStyle,
                         JoinStyle joinStyle,
                         double mitreLimit)
     : this(quadrantSegments, endCapStyle)
 {
     JoinStyle  = joinStyle;
     MitreLimit = mitreLimit;
 }
예제 #3
0
 /// <summary>
 /// Creates a set of parameters with the
 /// given parameter values.
 /// </summary>
 /// <param name="quadrantSegments"> the number of quadrant segments to use</param>
 /// <param name="endCapStyle"> the end cap style to use</param>
 /// <param name="joinStyle"> the join style to use</param>
 /// <param name="mitreLimit"> the mitre limit to use</param>
 public BufferParameters(int quadrantSegments,
     EndCapStyle endCapStyle,
     JoinStyle joinStyle,
     double mitreLimit)
     : this(quadrantSegments, endCapStyle)
 {
     JoinStyle = joinStyle;
     MitreLimit = mitreLimit;
 }
 private void ParseArgs(Object[] args)
 {
     _argCount = args.Length;
     _distance = Double.Parse((String)args[0]);
     if (_argCount >= 2)
     {
         _quadSegments = Int32.Parse((String)args[1]);
     }
     if (_argCount >= 3)
     {
         _endCapStyle = (EndCapStyle)Int32.Parse((String)args[2]);
     }
 }
        private static EndType Convert(EndCapStyle style)
        {
            switch (style)
            {
            case EndCapStyle.Round: return(EndType.etOpenRound);

            case EndCapStyle.Square: return(EndType.etOpenSquare);

            case EndCapStyle.Butt:
            default:
                return(EndType.etOpenButt);
            }
        }
예제 #6
0
 private void ParseArgs(object[] args)
 {
     _argCount = args.Length;
     _distance = double.Parse((string)args[0]);
     if (_argCount >= 2)
     {
         _quadSegments = int.Parse((string)args[1]);
     }
     if (_argCount >= 3)
     {
         _endCapStyle = (EndCapStyle)int.Parse((string)args[2]);
     }
 }
예제 #7
0
        /// <summary>
        /// Generates a buffer, but also adds the newly created feature to the specified output featureset.
        /// This will also compare the field names of the input featureset with the destination featureset.
        /// If a column name exists in both places, it will copy those values to the destination featureset.
        /// </summary>
        /// <param name="self">The feature to calcualate the buffer for.</param>
        /// <param name="distance">The double distance to use for calculating the buffer</param>
        /// <param name="endCapStyle">The end cap style to use</param>
        /// <param name="destinationFeatureset">The output featureset to add this feature to and use
        /// as a reference for determining which data columns to copy.</param>
        /// <returns>The IFeature that represents the buffer feature.</returns>
        public static IFeature Buffer(this IFeature self, double distance, EndCapStyle endCapStyle, IFeatureSet destinationFeatureset)
        {
            IFeature f = Buffer(self, distance, endCapStyle);

            destinationFeatureset.Features.Add(f);
            foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
            {
                if (self.DataRow[dc.ColumnName] != null)
                {
                    f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                }
            }
            return(f);
        }
예제 #8
0
        public void Dump(XmlWriter writer, SwfTagCode shapeType)
        {
            writer.WriteStartElement("line-style");
            writer.WriteAttributeString("width", Width.ToString());
            if (shapeType == SwfTagCode.DefineMorphShape)
            {
                writer.WriteAttributeString("end-width", EndWidth.ToString());
                writer.WriteAttributeString("color", Color.ToHtmlHex());
                writer.WriteAttributeString("end-color", EndColor.ToHtmlHex());
            }
            else if (shapeType == SwfTagCode.DefineShape4 || shapeType == SwfTagCode.DefineMorphShape2)
            {
                bool isMorph = shapeType == SwfTagCode.DefineMorphShape2;
                if (isMorph)
                {
                    writer.WriteAttributeString("end-width", EndWidth.ToString());
                }

                writer.WriteAttributeString("start-cap", StartCapStyle.ToString());
                writer.WriteAttributeString("end-cap", EndCapStyle.ToString());
                writer.WriteAttributeString("flags", Flags.ToString());

                if (JoinStyle == SwfJoinStyle.Miter)
                {
                    writer.WriteAttributeString("miter-limit", MiterLimit.ToString());
                }

                if (Fill != null)
                {
                    Fill.Dump(writer, shapeType);
                }
                else
                {
                    writer.WriteAttributeString("color", Color.ToHtmlHex());
                    if (isMorph)
                    {
                        writer.WriteAttributeString("end-color", EndColor.ToHtmlHex());
                    }
                }
            }
            else
            {
                writer.WriteAttributeString("color", Color.ToHtmlHex(shapeType == SwfTagCode.DefineShape3));
            }
            writer.WriteEndElement();
        }
 /// <summary>
 /// Creates a set of parameters with the
 /// given quadrantSegments and endCapStyle values.
 /// </summary>
 /// <param name="quadrantSegments"> the number of quadrant segments to use</param>
 /// <param name="endCapStyle"> the end cap style to use</param>
 public BufferParameters(int quadrantSegments,
     EndCapStyle endCapStyle)
     : this(quadrantSegments)
 {
     EndCapStyle = endCapStyle;
 }
예제 #10
0
 /// <summary>
 /// Computes a buffer region around this <c>Geometry</c> having the given width.
 /// The buffer of a Geometry is the Minkowski sum or difference of the geometry
 /// with a disc of radius <c>Abs(distance)</c>.
 /// </summary>
 /// <remarks>
 /// <para>The end cap style specifies the buffer geometry that will be
 /// created at the ends of linestrings.  The styles provided are:
 /// <ul>
 /// <li><see cref="EndCapStyle.Round" /> - (default) a semi-circle</li>
 /// <li><see cref="EndCapStyle.Flat" /> - a straight line perpendicular to the end segment</li>
 /// <li><see cref="EndCapStyle.Square" /> - a half-square</li>
 /// </ul></para>
 /// <para>The buffer operation always returns a polygonal result. The negative or
 /// zero-distance buffer of lines and points is always an empty <see cref="IPolygonal"/>.</para>
 /// </remarks>
 /// <param name="distance">
 /// The width of the buffer, interpreted according to the
 /// <c>PrecisionModel</c> of the <c>Geometry</c>.
 /// </param>
 /// <param name="endCapStyle">Cap Style to use for compute buffer.</param>
 /// <returns>
 /// a polygonal geometry representing the buffer region (which may be empty)
 /// </returns>
 /// <exception cref="TopologyException">If a robustness error occurs</exception>
 /// <seealso cref="Buffer(double)"/>
 /// <seealso cref="Buffer(double, IBufferParameters)"/>
 /// <seealso cref="Buffer(double, int)"/>
 /// <seealso cref="Buffer(double, int, EndCapStyle)"/>
 public IGeometry Buffer(double distance, EndCapStyle endCapStyle)
 {
     return BufferOp.Buffer(this, distance, BufferParameters.DefaultQuadrantSegments, (BufferStyle)endCapStyle);
 }
예제 #11
0
        /// <summary>
        /// Generates a new feature from the buffer of this feature.  The DataRow of
        /// the new feature will be null.
        /// </summary>
        /// <param name="self">This feature</param>
        /// <param name="distance">The double distance</param>
        /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle</param>
        /// <param name="endCapStyle">The end cap style to use</param>
        /// <returns>An IFeature representing the output from the buffer operation</returns>
        public static IFeature Buffer(this IFeature self, double distance, int quadrantSegments, EndCapStyle endCapStyle)
        {
            IGeometry g = self.Geometry.Buffer(distance, quadrantSegments, endCapStyle);

            return(new Feature(g));
        }
예제 #12
0
 /// <summary>
 /// Computes a buffer region around this <c>Geometry</c> having the given
 /// width and with a specified number of segments used to approximate curves.
 /// The buffer of a Geometry is the Minkowski sum of the Geometry with
 /// a disc of radius <c>distance</c>.  Curves in the buffer polygon are
 /// approximated with line segments.  This method allows specifying the
 /// accuracy of that approximation.
 /// </summary>
 /// <remarks><para>Mathematically-exact buffer area boundaries can contain circular arcs. 
 /// To represent these arcs using linear geometry they must be approximated with line segments.
 /// The <c>quadrantSegments</c> argument allows controlling the accuracy of
 /// the approximation by specifying the number of line segments used to
 /// represent a quadrant of a circle</para>
 /// <para>The end cap style specifies the buffer geometry that will be
 /// created at the ends of linestrings.  The styles provided are:
 /// <ul>
 /// <li><see cref="EndCapStyle.Round" /> - (default) a semi-circle</li>
 /// <li><see cref="EndCapStyle.Flat" /> - a straight line perpendicular to the end segment</li>
 /// <li><see cref="EndCapStyle.Square" /> - a half-square</li>
 /// </ul></para>
 /// <para>The buffer operation always returns a polygonal result. The negative or
 /// zero-distance buffer of lines and points is always an empty <see cref="IPolygonal"/>.
 /// This is also the result for the buffers of degenerate (zero-area) polygons.
 /// </para>
 /// </remarks>
 /// <param name="distance">
 /// The width of the buffer, interpreted according to the
 /// <c>PrecisionModel</c> of the <c>Geometry</c>.
 /// </param>
 /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle.</param>
 /// <param name="endCapStyle">Cap Style to use for compute buffer.</param>
 /// <returns>
 /// a polygonal geometry representing the buffer region (which may be empty)
 /// </returns>
 /// <exception cref="TopologyException">If a robustness error occurs</exception>
 /// <seealso cref="Buffer(double)"/>
 /// <seealso cref="Buffer(double, EndCapStyle)"/>
 /// <seealso cref="Buffer(double, IBufferParameters)"/>
 /// <seealso cref="Buffer(double, int)"/>
 public IGeometry Buffer(double distance, int quadrantSegments, EndCapStyle endCapStyle)
 {
     return BufferOp.Buffer(this, distance, quadrantSegments, (BufferStyle)endCapStyle);
 }
 private void ParseArgs(Object[] args)
 {
     _argCount = args.Length;
     _distance = Double.Parse((String)args[0]);
     if (_argCount >= 2)
         _quadSegments = Int32.Parse((String)args[1]);
     if (_argCount >= 3)
         _endCapStyle = (EndCapStyle)Int32.Parse((String)args[2]);
 }
        /// <summary>
        /// Generates an outline of the path.
        /// </summary>
        /// <param name="path">The path to outline</param>
        /// <param name="width">The outline width.</param>
        /// <param name="jointStyle">The style to apply to the joints.</param>
        /// <param name="endCapStyle">The style to apply to the end caps.</param>
        /// <returns>A new <see cref="IPath"/> representing the outline.</returns>
        /// <exception cref="ClipperException">Thrown when an offset cannot be calculated.</exception>
        public static IPath GenerateOutline(this IPath path, float width, JointStyle jointStyle, EndCapStyle endCapStyle)
        {
            ClipperOffset offset = new(MiterOffsetDelta);

            offset.AddPath(path, jointStyle, endCapStyle);

            return(offset.Execute(width));
        }
 /// <summary>
 /// Creates a set of parameters with the
 /// given quadrantSegments and endCapStyle values.
 /// </summary>
 /// <param name="quadrantSegments"> the number of quadrant segments to use</param>
 /// <param name="endCapStyle"> the end cap style to use</param>
 public BufferParameters(int quadrantSegments,
                         EndCapStyle endCapStyle)
     : this(quadrantSegments)
 {
     EndCapStyle = endCapStyle;
 }
예제 #16
0
        private static void OutputStarOutlineDashed(int points, float inner = 10, float outer = 20, float width = 5, JointStyle jointStyle = JointStyle.Miter, EndCapStyle cap = EndCapStyle.Butt)
        {
            // center the shape outerRadii + 10 px away from edges
            float offset = outer + 10;

            Star star    = new Star(offset, offset, points, inner, outer);
            var  outline = Outliner.GenerateOutline(star, width, new float[] { 3, 3 }, false, jointStyle, cap);

            outline.SaveImage("Stars", $"StarOutlineDashed_{points}_{jointStyle}_{cap}.png");
        }
예제 #17
0
        /// <summary>
        /// Generates a outline of the path with alternating on and off segments based on the pattern.
        /// </summary>
        /// <param name="path">the path to outline</param>
        /// <param name="width">The final width outline</param>
        /// <param name="pattern">The pattern made of multiples of the width.</param>
        /// <param name="startOff">Weather the first item in the pattern is on or off.</param>
        /// <param name="jointStyle">The style to render the joints.</param>
        /// <param name="patternSectionCapStyle">The style to render between sections of the specified pattern.</param>
        /// <returns>A new path representing the outline.</returns>
        public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan <float> pattern, bool startOff, JointStyle jointStyle = JointStyle.Square, EndCapStyle patternSectionCapStyle = EndCapStyle.Butt)
        {
            if (pattern.Length < 2)
            {
                return(path.GenerateOutline(width, jointStyle: jointStyle));
            }

            JoinType style             = Convert(jointStyle);
            EndType  patternSectionCap = Convert(patternSectionCapStyle);

            IEnumerable <ISimplePath> paths = path.Flatten();

            var offset = new ClipperOffset()
            {
                MiterLimit = MiterOffsetDelta
            };

            var buffer = new List <IntPoint>(3);

            foreach (ISimplePath p in paths)
            {
                bool  online       = !startOff;
                float targetLength = pattern[0] * width;
                int   patternPos   = 0;

                // Create a new list of points representing the new outline
                int pCount = p.Points.Count;
                if (!p.IsClosed)
                {
                    pCount--;
                }

                int     i            = 0;
                Vector2 currentPoint = p.Points[0];

                while (i < pCount)
                {
                    int     next        = (i + 1) % p.Points.Count;
                    Vector2 targetPoint = p.Points[next];
                    float   distToNext  = Vector2.Distance(currentPoint, targetPoint);
                    if (distToNext > targetLength)
                    {
                        // find a point between the 2
                        float t = targetLength / distToNext;

                        Vector2 point = (currentPoint * (1 - t)) + (targetPoint * t);
                        buffer.Add(currentPoint.ToPoint());
                        buffer.Add(point.ToPoint());

                        // we now inset a line joining
                        if (online)
                        {
                            offset.AddPath(buffer, style, patternSectionCap);
                        }

                        online = !online;

                        buffer.Clear();

                        currentPoint = point;

                        // next length
                        patternPos   = (patternPos + 1) % pattern.Length;
                        targetLength = pattern[patternPos] * width;
                    }
                    else if (distToNext <= targetLength)
                    {
                        buffer.Add(currentPoint.ToPoint());
                        currentPoint = targetPoint;
                        i++;
                        targetLength -= distToNext;
                    }
                }

                if (buffer.Count > 0)
                {
                    if (p.IsClosed)
                    {
                        buffer.Add(p.Points.First().ToPoint());
                    }
                    else
                    {
                        buffer.Add(p.Points.Last().ToPoint());
                    }

                    if (online)
                    {
                        offset.AddPath(buffer, style, patternSectionCap);
                    }

                    online = !online;

                    buffer.Clear();
                    patternPos   = (patternPos + 1) % pattern.Length;
                    targetLength = pattern[patternPos] * width;
                }
            }

            return(ExecuteOutliner(width, offset));
        }
예제 #18
0
        /// <summary>
        /// Generates a solid outline of the path.
        /// </summary>
        /// <param name="path">the path to outline</param>
        /// <param name="width">The final width outline</param>
        /// <param name="jointStyle">The style to render the joints.</param>
        /// <param name="endCapStyle">The style to render the end caps of open paths (ignored on closed paths).</param>
        /// <returns>A new path representing the outline.</returns>
        public static IPath GenerateOutline(this IPath path, float width, JointStyle jointStyle = JointStyle.Square, EndCapStyle endCapStyle = EndCapStyle.Square)
        {
            var offset = new ClipperOffset()
            {
                MiterLimit = MiterOffsetDelta
            };

            JoinType style           = Convert(jointStyle);
            EndType  openEndCapStyle = Convert(endCapStyle);

            // Pattern can be applied to the path by cutting it into segments
            IEnumerable <ISimplePath> paths = path.Flatten();

            foreach (ISimplePath p in paths)
            {
                IReadOnlyList <PointF> vectors = p.Points;
                var points = new List <IntPoint>(vectors.Count);
                foreach (Vector2 v in vectors)
                {
                    points.Add(new IntPoint(v.X * ScalingFactor, v.Y * ScalingFactor));
                }

                EndType type = p.IsClosed ? EndType.etClosedLine : openEndCapStyle;

                offset.AddPath(points, style, type);
            }

            return(ExecuteOutliner(width, offset));
        }
        /// <summary>
        /// Generates an outline of the path with alternating on and off segments based on the pattern.
        /// </summary>
        /// <param name="path">The path to outline</param>
        /// <param name="width">The outline width.</param>
        /// <param name="pattern">The pattern made of multiples of the width.</param>
        /// <param name="startOff">Whether the first item in the pattern is on or off.</param>
        /// <param name="jointStyle">The style to apply to the joints.</param>
        /// <param name="endCapStyle">The style to apply to the end caps.</param>
        /// <returns>A new <see cref="IPath"/> representing the outline.</returns>
        /// <exception cref="ClipperException">Thrown when an offset cannot be calculated.</exception>
        public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan <float> pattern, bool startOff, JointStyle jointStyle, EndCapStyle endCapStyle)
        {
            if (pattern.Length < 2)
            {
                return(path.GenerateOutline(width, jointStyle, endCapStyle));
            }

            IEnumerable <ISimplePath> paths = path.Flatten();

            ClipperOffset offset = new(MiterOffsetDelta);
            List <PointF> buffer = new();

            foreach (ISimplePath p in paths)
            {
                bool  online                 = !startOff;
                float targetLength           = pattern[0] * width;
                int   patternPos             = 0;
                ReadOnlySpan <PointF> points = p.Points.Span;

                // Create a new list of points representing the new outline
                int pCount = points.Length;
                if (!p.IsClosed)
                {
                    pCount--;
                }

                int     i            = 0;
                Vector2 currentPoint = points[0];

                while (i < pCount)
                {
                    int     next        = (i + 1) % points.Length;
                    Vector2 targetPoint = points[next];
                    float   distToNext  = Vector2.Distance(currentPoint, targetPoint);
                    if (distToNext > targetLength)
                    {
                        // find a point between the 2
                        float t = targetLength / distToNext;

                        Vector2 point = (currentPoint * (1 - t)) + (targetPoint * t);
                        buffer.Add(currentPoint);
                        buffer.Add(point);

                        // we now inset a line joining
                        if (online)
                        {
                            offset.AddPath(new ReadOnlySpan <PointF>(buffer.ToArray()), jointStyle, endCapStyle);
                        }

                        online = !online;

                        buffer.Clear();

                        currentPoint = point;

                        // next length
                        patternPos   = (patternPos + 1) % pattern.Length;
                        targetLength = pattern[patternPos] * width;
                    }
                    else if (distToNext <= targetLength)
                    {
                        buffer.Add(currentPoint);
                        currentPoint = targetPoint;
                        i++;
                        targetLength -= distToNext;
                    }
                }

                if (buffer.Count > 0)
                {
                    if (p.IsClosed)
                    {
                        buffer.Add(points[0]);
                    }
                    else
                    {
                        buffer.Add(points[points.Length - 1]);
                    }

                    if (online)
                    {
                        offset.AddPath(new ReadOnlySpan <PointF>(buffer.ToArray()), jointStyle, endCapStyle);
                    }

                    online = !online;

                    buffer.Clear();
                    patternPos   = (patternPos + 1) % pattern.Length;
                    targetLength = pattern[patternPos] * width;
                }
            }

            return(offset.Execute(width));
        }
 /// <summary>
 /// Generates an outline of the path with alternating on and off segments based on the pattern.
 /// </summary>
 /// <param name="path">The path to outline</param>
 /// <param name="width">The outline width.</param>
 /// <param name="pattern">The pattern made of multiples of the width.</param>
 /// <param name="jointStyle">The style to apply to the joints.</param>
 /// <param name="endCapStyle">The style to apply to the end caps.</param>
 /// <returns>A new <see cref="IPath"/> representing the outline.</returns>
 /// <exception cref="ClipperException">Thrown when an offset cannot be calculated.</exception>
 public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan <float> pattern, JointStyle jointStyle, EndCapStyle endCapStyle)
 => GenerateOutline(path, width, pattern, false, jointStyle, endCapStyle);