Esempio n. 1
0
        /// <summary>
        /// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="ISvgRenderer"/>
        /// </summary>
        /// <param name="renderer">The <see cref="ISvgRenderer"/> object to render to.</param>
        /// <param name="stroke"></param>
        protected internal virtual bool RenderStroke(ISvgRenderer renderer, SvgPaintServer stroke = null)
        {
            stroke = stroke ?? Stroke;

            if (stroke != null && stroke != SvgPaintServer.None)
            {
                var strokeWidth = StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this);

                renderer.DrawPath(Path(renderer), stroke.GetColor(this, renderer, FixOpacityValue(StrokeOpacity), true), strokeWidth);
                return(true);
            }

            return(false);
        }
Esempio n. 2
0
        /// <summary>
        /// Create a pen that can be used to render this marker
        /// </summary>
        /// <param name="pStroke"></param>
        /// <returns></returns>
        private Pen CreatePen(SvgPath pPath, SvgRenderer renderer)
        {
            Brush pBrush = pPath.Stroke.GetBrush(this, renderer, Opacity);

            switch (MarkerUnits)
            {
            case SvgMarkerUnits.strokeWidth:
                return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this) *
                               pPath.StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));

            case SvgMarkerUnits.userSpaceOnUse:
                return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
            }
            return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
        }
Esempio n. 3
0
        /// <summary>
        /// Create a pen that can be used to render this marker
        /// </summary>
        /// <returns></returns>
        private Pen CreatePen(SvgVisualElement pPath, ISvgRenderer renderer)
        {
            if (pPath.Stroke == null)
            {
                return(null);
            }
            Brush pBrush = pPath.Stroke.GetBrush(this, renderer, Opacity);

            switch (MarkerUnits)
            {
            case SvgMarkerUnits.StrokeWidth:
                return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this) *
                               pPath.StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));

            case SvgMarkerUnits.UserSpaceOnUse:
                return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
            }
            return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
        }
Esempio n. 4
0
        /// <summary>
        /// Create a pen that can be used to render this marker
        /// </summary>
        /// <returns></returns>
        private Pen CreatePen(SvgVisualElement pPath, ISvgRenderer renderer)
        {
            if (this.Stroke == null)
            {
                return(null);
            }
            Brush pBrush = this.Stroke.GetBrush(this, renderer, FixOpacityValue(Opacity));

            switch (MarkerUnits)
            {
            case SvgMarkerUnits.StrokeWidth:
                // TODO: have to multiply with marker stroke width if it is not inherted from the
                // same ancestor as owner path stroke width
                return(new Pen(pBrush, pPath.StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));

            case SvgMarkerUnits.UserSpaceOnUse:
                return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
            }
            return(new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
        }
Esempio n. 5
0
        /// <summary>
        /// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="ISvgRenderer"/>
        /// </summary>
        /// <param name="renderer">The <see cref="ISvgRenderer"/> object to render to.</param>
        protected internal virtual bool RenderStroke(ISvgRenderer renderer)
        {
            if (Stroke != null && Stroke != SvgPaintServer.None && StrokeWidth > 0f)
            {
                var strokeWidth = StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this);
                using (var brush = Stroke.GetBrush(this, renderer, Math.Min(Math.Max(StrokeOpacity, 0f), 1f), true))
                {
                    if (brush != null)
                    {
                        var path   = Path(renderer);
                        var bounds = path.GetBounds();
                        if (path.PointCount < 1)
                        {
                            return(false);
                        }
                        if (bounds.Width <= 0f && bounds.Height <= 0f)
                        {
                            switch (StrokeLineCap)
                            {
                            case SvgStrokeLineCap.Round:
                                using (var capPath = new GraphicsPath())
                                {
                                    capPath.AddEllipse(path.PathPoints[0].X - strokeWidth / 2f, path.PathPoints[0].Y - strokeWidth / 2f, strokeWidth, strokeWidth);
                                    renderer.FillPath(brush, capPath);
                                }
                                break;

                            case SvgStrokeLineCap.Square:
                                using (var capPath = new GraphicsPath())
                                {
                                    capPath.AddRectangle(new RectangleF(path.PathPoints[0].X - strokeWidth / 2f, path.PathPoints[0].Y - strokeWidth / 2f, strokeWidth, strokeWidth));
                                    renderer.FillPath(brush, capPath);
                                }
                                break;
                            }
                        }
                        else
                        {
                            using (var pen = new Pen(brush, strokeWidth))
                            {
                                if (StrokeDashArray != null && StrokeDashArray.Count > 0)
                                {
                                    strokeWidth = strokeWidth <= 0 ? 1f : strokeWidth;
                                    if (StrokeDashArray.Count % 2 != 0)
                                    {
                                        // handle odd dash arrays by repeating them once
                                        StrokeDashArray.AddRange(StrokeDashArray);
                                    }

                                    var dashOffset = StrokeDashOffset;

                                    /* divide by stroke width - GDI uses stroke width as unit.*/
                                    var dashPattern = StrokeDashArray.Select(u => ((u.ToDeviceValue(renderer, UnitRenderingType.Other, this) <= 0f) ? 1f :
                                                                                   u.ToDeviceValue(renderer, UnitRenderingType.Other, this)) / strokeWidth).ToArray();
                                    var length = dashPattern.Length;

                                    if (StrokeLineCap == SvgStrokeLineCap.Round)
                                    {
                                        // to handle round caps, we have to adapt the dash pattern
                                        // by increasing the dash length by the stroke width - GDI draws the rounded
                                        // edge inside the dash line, SVG draws it outside the line
                                        var pattern = new float[length];
                                        var offset  = 1; // the values are already normalized to dash width
                                        for (var i = 0; i < length; i++)
                                        {
                                            pattern[i] = dashPattern[i] + offset;
                                            if (pattern[i] <= 0f)
                                            {
                                                // overlapping caps - remove the gap for simplicity, see #508
                                                if (i < length - 1)
                                                {
                                                    // add the next dash segment to the current one
                                                    dashPattern[i - 1] += dashPattern[i] + dashPattern[i + 1];
                                                    length             -= 2;
                                                    for (var k = i; k < length; k++)
                                                    {
                                                        dashPattern[k] = dashPattern[k + 2];
                                                    }

                                                    // and handle the combined segment again
                                                    i -= 2;
                                                }
                                                else if (i > 2)
                                                {
                                                    // add the last dash segment to the first one
                                                    // this will change the start point, so adapt the offset
                                                    var dashLength = dashPattern[i - 1] + dashPattern[i];
                                                    pattern[0] += dashLength;
                                                    length     -= 2;
                                                    dashOffset += dashLength * strokeWidth;
                                                }
                                                else
                                                {
                                                    // we have only one dash with the gap too small -
                                                    // do not use dash at all
                                                    length = 0;
                                                    break;
                                                }
                                            }
                                            offset *= -1; // increase dash length, decrease spaces
                                        }
                                        if (length > 0)
                                        {
                                            if (length < dashPattern.Length)
                                            {
                                                Array.Resize(ref pattern, length);
                                            }
                                            dashPattern = pattern;
                                            pen.DashCap = DashCap.Round;
                                        }
                                    }

                                    if (length > 0)
                                    {
                                        pen.DashPattern = dashPattern;

                                        if (dashOffset != 0f)
                                        {
                                            pen.DashOffset = ((dashOffset.ToDeviceValue(renderer, UnitRenderingType.Other, this) <= 0f) ? 1f :
                                                              dashOffset.ToDeviceValue(renderer, UnitRenderingType.Other, this)) / strokeWidth;
                                        }
                                    }
                                }
                                switch (StrokeLineJoin)
                                {
                                case SvgStrokeLineJoin.Bevel:
                                    pen.LineJoin = LineJoin.Bevel;
                                    break;

                                case SvgStrokeLineJoin.Round:
                                    pen.LineJoin = LineJoin.Round;
                                    break;

                                default:
                                    pen.LineJoin = LineJoin.Miter;
                                    break;
                                }
                                pen.MiterLimit = StrokeMiterLimit;
                                switch (StrokeLineCap)
                                {
                                case SvgStrokeLineCap.Round:
                                    pen.StartCap = LineCap.Round;
                                    pen.EndCap   = LineCap.Round;
                                    break;

                                case SvgStrokeLineCap.Square:
                                    pen.StartCap = LineCap.Square;
                                    pen.EndCap   = LineCap.Square;
                                    break;
                                }

                                renderer.DrawPath(pen, path);

                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }