public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv)
        {
            if (!conv.TrySplitValues(commandString.Substring(1), out var values, false))
            {
                yield break;
            }

            int valuePos = 0;

            while (valuePos < values.Length)
            {
                var start = new Pnt2d();
                if (lastSegment != null)
                {
                    start = lastSegment.End;
                }

                double      rx    = values[0] * conv.Scale;
                double      ry    = values[1] * conv.Scale;
                double      angle = values[2];
                SvgArcSize  size  = values[3] == 0 ? SvgArcSize.Small : SvgArcSize.Large;
                SvgArcSweep sweep = values[4] == 0 ? SvgArcSweep.Negative : SvgArcSweep.Positive;
                Pnt2d       end   = new Pnt2d(values[5] * conv.Scale, values[6] * conv.Scale);
                if (char.IsLower(commandString[0]))
                {
                    end += start;
                }
                valuePos += 7;

                lastSegment = new SvgPathSegArc(start, rx, ry, angle, size, sweep, end);
                yield return(lastSegment);
            }
        }
        public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv)
        {
            if (!conv.TrySplitValues(commandString.Substring(1), out var values, true))
            {
                yield break;
            }

            int valuePos = 0;

            while (valuePos < values.Length)
            {
                var start = lastSegment?.End ?? Pnt2d.Origin;

                Pnt2d c1;
                Pnt2d c2;
                Pnt2d end;
                if (char.ToLower(commandString[0]) == 'c')
                {
                    c1        = new Pnt2d(values[valuePos], values[valuePos + 1]);
                    c2        = new Pnt2d(values[valuePos + 2], values[valuePos + 3]);
                    end       = new Pnt2d(values[valuePos + 4], values[valuePos + 5]);
                    valuePos += 6;

                    if (char.IsLower(commandString[0]))
                    {
                        c1  += start;
                        c2  += start;
                        end += start;
                    }
                    lastSegment = new SvgPathSegCurvetoCubic(start, c1, c2, end);
                    yield return(lastSegment);
                }
                else if (char.ToLower(commandString[0]) == 's')
                {
                    c2        = new Pnt2d(values[valuePos], values[valuePos + 1]);
                    end       = new Pnt2d(values[valuePos + 2], values[valuePos + 3]);
                    valuePos += 4;

                    if (char.IsLower(commandString[0]))
                    {
                        c2  += start;
                        end += start;
                    }

                    if (lastSegment is SvgPathSegCurvetoCubic lastSeg)
                    {
                        c1 = lastSeg.C2;
                    }
                    else
                    {
                        c1 = c2;
                    }
                    lastSegment = new SvgPathSegCurvetoCubic(start, c1, c2, end);
                    yield return(lastSegment);
                }
            }
        }
        public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv)
        {
            if (!conv.TrySplitValues(commandString.Substring(1), out var values, true))
            {
                yield break;
            }

            int valuePos = 0;

            while (valuePos < values.Length)
            {
                var start = lastSegment?.End ?? Pnt2d.Origin;

                SvgPathSegLineto segment = null;
                switch (commandString[0])
                {
                case 'L':
                    segment   = new SvgPathSegLineto(start, new Pnt2d(values[valuePos], values[valuePos + 1]));
                    valuePos += 2;
                    break;

                case 'l':
                    segment   = new SvgPathSegLineto(start, start + new Pnt2d(values[valuePos], values[valuePos + 1]));
                    valuePos += 2;
                    break;

                case 'H':
                    segment   = new SvgPathSegLineto(start, new Pnt2d(values[valuePos], start.Y));
                    valuePos += 1;
                    break;

                case 'h':
                    segment   = new SvgPathSegLineto(start, start + new Pnt2d(values[valuePos], 0));
                    valuePos += 1;
                    break;

                case 'V':
                    segment   = new SvgPathSegLineto(start, new Pnt2d(start.X, values[valuePos]));
                    valuePos += 1;
                    break;

                case 'v':
                    segment   = new SvgPathSegLineto(start, start + new Pnt2d(0, values[valuePos]));
                    valuePos += 1;
                    break;
                }
                yield return(segment);

                lastSegment = segment;
            }
        }
        internal static IEnumerable <SvgTransform> Create(string transformString, SvgConverter conv)
        {
            var transformParts = transformString.Split(_TransformSplitChars);

            for (int i = 0; i < transformParts.Length - 1; i += 2)
            {
                if (!conv.TrySplitValues(transformParts[i + 1], out var values, false))
                {
                    continue;
                }

                SvgTransform transform;
                switch (transformParts[i].ToLower().Trim())
                {
                case "matrix":
                    transform = SvgMatrixTransform.Create(values, conv);
                    break;

                case "translate":
                    transform = SvgTranslateTransform.Create(values, conv);
                    break;

                case "scale":
                    transform = SvgScaleTransform.Create(values, conv);
                    break;

                case "rotate":
                    transform = SvgRotateTransform.Create(values, conv);
                    break;

                case "skewx":
                    transform = SvgSkewXTransform.Create(values, conv);
                    break;

                case "skewy":
                    transform = SvgSkewYTransform.Create(values, conv);
                    break;

                default:
                    Messages.Warning($"Unknown transform type {transformParts[i]} found in SVG file.");
                    continue;
                }

                if (transform != null)
                {
                    yield return(transform);
                }
            }
        }
        //--------------------------------------------------------------------------------------------------

        void _CalculateScale(XmlReader reader, SvgConverter conv)
        {
            var viewBox = reader.GetAttribute("viewBox");

            if (viewBox.IsNullOrWhiteSpace() || !conv.TrySplitValues(viewBox, out var viewBoxValues, false))
            {
                Messages.Warning("SVG document has not defined a ViewBox. The scaling may be incorrect.");
                return;
            }

            double fScaleX = 1.0;
            double fScaleY = 1.0;

            if (conv.TryConvertToMillimeter(reader.GetAttribute("width"), out var width, false) &&
                conv.TryConvertToMillimeter(reader.GetAttribute("height"), out var height, false))
            {
                fScaleX = width / viewBoxValues[2];
                fScaleY = height / viewBoxValues[3];
            }
        public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv)
        {
            if (!conv.TrySplitValues(commandString.Substring(1), out var values, true))
            {
                yield break;
            }

            bool  isRelative = commandString[0] == 'm';
            int   valuePos   = 0;
            Pnt2d endPoint   = new Pnt2d();

            if (valuePos < values.Length)
            {
                endPoint = new Pnt2d(values[valuePos], values[valuePos + 1]);
                if (isRelative && lastSegment != null)
                {
                    endPoint += lastSegment.End;
                }
                yield return(new SvgPathSegMoveto(endPoint));

                valuePos += 2;
            }

            // subsequent value pairs are implicit lineto's
            while (valuePos < values.Length)
            {
                var startPoint = endPoint;
                endPoint = new Pnt2d(values[valuePos], values[valuePos + 1]);
                if (isRelative)
                {
                    endPoint += startPoint;
                }
                yield return(new SvgPathSegLineto(startPoint, endPoint));

                valuePos += 2;
            }
        }