Beispiel #1
0
            public void EndGlyph()
            {
                GlyphRenderData renderData = default;

                // has the glyoh been rendedered already????
                if (this.raterizationRequired)
                {
                    IPath path = this.builder.Build();

                    if (this.renderFill)
                    {
                        renderData.FillMap = this.Render(path);
                    }

                    if (this.renderOutline)
                    {
                        if (this.Pen.StrokePattern.Length == 0)
                        {
                            path = path.GenerateOutline(this.Pen.StrokeWidth);
                        }
                        else
                        {
                            path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern);
                        }

                        renderData.OutlineMap = this.Render(path);
                    }

                    this.glyphData[this.currentGlyphRenderParams] = renderData;
                }
                else
                {
                    renderData = this.glyphData[this.currentGlyphRenderParams];
                }

                if (this.renderFill)
                {
                    this.FillOperations.Add(new DrawingOperation
                    {
                        Location = this.currentRenderPosition,
                        Map      = renderData.FillMap
                    });
                }

                if (this.renderOutline)
                {
                    this.OutlineOperations.Add(new DrawingOperation
                    {
                        Location = this.currentRenderPosition,
                        Map      = renderData.OutlineMap
                    });
                }
            }
Beispiel #2
0
        private void RenderShapeToCanvas(SvgGraphicsElement svgGraphicsElement, IPath path)
        {
            var matrix = CalulateUpdatedMatrix(svgGraphicsElement);

            var brush = svgGraphicsElement.CreateFillPaintServer()?.Accept(BrushGenerator <TPixel> .Instance);

            IBrush strokFill = null;
            IPath  outline   = null;

            if (svgGraphicsElement.StrokeWidth > 0)
            {
                strokFill = svgGraphicsElement.CreateStrokePaintServer()?.Accept(BrushGenerator <TPixel> .Instance);
                if (strokFill != null)
                {
                    var pattern = svgGraphicsElement.Style.StrokeDashArray.Value?.Select(X => X.Value).ToArray();
                    var joint   = svgGraphicsElement.Style.StrokeLineJoin.AsJointStyle();
                    var end     = svgGraphicsElement.Style.StrokeLineCap.AsEndCapStyle();
                    if (pattern == null || pattern.Length == 0)
                    {
                        outline = path.GenerateOutline(svgGraphicsElement.StrokeWidth, joint, end);
                    }
                    else
                    {
                        outline = path.GenerateOutline(svgGraphicsElement.StrokeWidth,
                                                       pattern,
                                                       false,
                                                       joint, end);
                    }
                }
            }

            var shapeOptions = new ShapeOptions {
                IntersectionRule = IntersectionRule.Nonzero
            };
            var shapeGraphicsOptions = new DrawingOptions()
            {
                ShapeOptions = shapeOptions
            };

            if (brush != null)
            {
                image.Fill(shapeGraphicsOptions, brush, path.Transform(matrix));
            }

            if (outline != null && strokFill != null)
            {
                image.Fill(shapeGraphicsOptions, strokFill, outline.Transform(matrix));
            }
        }
        public void ClippedTriangleGapInIntersections()
        {
            Polygon simplePath = new Polygon(new LinearLineSegment(
                                                 new PointF(10, 10),
                                                 new PointF(200, 150),
                                                 new PointF(50, 300)));

            Polygon hole1 = new Polygon(new LinearLineSegment(
                                            new PointF(37, 85),
                                            new PointF(93, 85),
                                            new PointF(65, 137)));

            IPath clippedPath = simplePath.Clip(hole1);
            IPath outline     = clippedPath.GenerateOutline(5, new[] { 1f });

            PointF[] buffer = new PointF[20];

            PointF start = new PointF(outline.Bounds.Left - 1, 102);
            PointF end   = new PointF(outline.Bounds.Right + 1, 102);

            int matches  = outline.FindIntersections(start, end, buffer, 0);
            int maxIndex = buffer.Select((x, i) => new { x, i }).Where(x => x.x.X > 0).Select(x => x.i).Last();

            Assert.Equal(matches - 1, maxIndex);
        }
Beispiel #4
0
        public void ClippedTriangle()
        {
            var simplePath = new Polygon(new LinearLineSegment(
                                             new PointF(10, 10),
                                             new PointF(200, 150),
                                             new PointF(50, 300)));

            var hole1 = new Polygon(new LinearLineSegment(
                                        new PointF(37, 85),
                                        new PointF(93, 85),
                                        new PointF(65, 137)));

            IPath clippedPath = simplePath.Clip(hole1);
            IPath outline     = clippedPath.GenerateOutline(5, new[] { 1f });

            Assert.False(outline.Contains(new PointF(74, 97)));
        }
Beispiel #5
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>
        /// <returns>A new path representing the outline.</returns>
        public static IPath GenerateOutline(this IPath path, float width, float[] pattern, bool startOff)
        {
            if (pattern == null || pattern.Length < 2)
            {
                return(path.GenerateOutline(width));
            }

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

            ClipperOffset offset = new ClipperOffset();

            List <IntPoint> 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, JoinType.jtSquare, EndType.etOpenButt);
                        }

                        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, JoinType.jtSquare, EndType.etOpenButt);
                    }

                    online = !online;

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

            return(ExecuteOutliner(width, offset));
        }
Beispiel #6
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>
 /// <returns>A new path representing the outline.</returns>
 public static IPath GenerateOutline(this IPath path, float width, float[] pattern)
 {
     return(path.GenerateOutline(width, pattern, false));
 }
Beispiel #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ShapePath"/> class.
 /// </summary>
 /// <param name="shape">The shape.</param>
 /// <param name="pen">The pen to apply to the shape.</param>
 public ShapePath(IPath shape, IPen pen)
     : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern))
 {
 }
Beispiel #8
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>
 /// <returns>A new path representing the outline.</returns>
 public static IPath GenerateOutline(this IPath path, float width, float[] pattern, bool startOff)
 => path.GenerateOutline(width, new ReadOnlySpan <float>(pattern), startOff);
Beispiel #9
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>
 /// <returns>A new path representing the outline.</returns>
 public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan <float> pattern)
 {
     return(path.GenerateOutline(width, pattern, false));
 }
        /// <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));
        }
Beispiel #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ShapePath"/> class.
 /// </summary>
 /// <param name="shape">The shape.</param>
 /// <param name="pen">The pen to apply to the shape.</param>
 // SixLabors.shape willbe moving to a Span/ReadOnlySpan based API shortly use ToArray for now.
 public ShapePath(IPath shape, Pens.IPen pen)
     : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern.ToArray()))
 {
 }
        /// <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));
        }