Exemple #1
0
        // Converting tracedata to an SVG string, paths are drawn according to a Z-index
        // the optional lcpr and qcpr are linear and quadratic control point radiuses
        public static string ToSvgString(this TracedImage image, SvgRendering options)
        {
            // SVG start
            var scaledWidth       = (int)(image.Width * options.Scale);
            var scaledHeight      = (int)(image.Height * options.Scale);
            var viewBoxOrViewPort = options.Viewbox ?
                                    $"viewBox=\"0 0 {scaledWidth} {scaledHeight}\"" :
                                    $"width=\"{scaledWidth}\" height=\"{scaledHeight}\"";

            var stringBuilder = new StringBuilder($"<svg {viewBoxOrViewPort} version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" >");

            // Creating Z-index
            // Only selecting the first segment of each path for sorting.
            // Sorting Z-index is not required, TreeMap is sorted automatically
            return(image.Layers
                   .SelectMany(cs => cs.Value.Paths.Select(p =>
            {
                var firstSegmentStart = p.Segments.First().Start;
                var label = firstSegmentStart.Y * scaledWidth + firstSegmentStart.X;
                return new ZPosition {
                    Label = label, Color = cs.Key, Path = p
                };
            })).OrderBy(z => z.Label)
                   .Aggregate(stringBuilder, (sb, z) =>
            {
                var scaledSegments = z.Path.Segments.Select(s => s.Scale(options.Scale)).ToList();
                return AppendSegments(sb, scaledSegments, z.Color);
            }).Append("</svg>").ToString());
        }
Exemple #2
0
        ////////////////////////////////////////////////////////////

        // Tracing ImageData, then returning PaddedPaletteImage with tracedata in layers
        private static TracedImage PaddedPaletteImageToTraceData(Bitmap image, Tracing tracing, SvgRendering rendering)
        {
            // Selective Gaussian blur preprocessing
            //if (options.Blur.BlurRadius > 0)
            //{
            //    // TODO: This seems to not work currently.
            //    imgd = Blur(imgd, options.Blur.BlurRadius, options.Blur.BlurDelta);
            //}

            // 1. Color quantization
            var colors      = image.ChangeFormat(PixelFormat.Format32bppArgb).ToColorReferences();
            var colorGroups = ColorGrouping.Convert(colors, image.Width, image.Height, Palette);
            // 2. Layer separation and edge detection
            var rawLayers = Layering.Convert(colorGroups, image.Width, image.Height, Palette);
            // 3. Batch pathscan
            var pathPointLayers = rawLayers.ToDictionary(cl => cl.Key, cl => new Layer <PathPointPath>
            {
                Paths = Pathing.Scan(cl.Value, tracing.PathOmit).ToList()
            });
            // 4. Batch interpollation
            var interpolationPointLayers = pathPointLayers.ToDictionary(cp => cp.Key, cp => Interpolation.Convert(cp.Value));
            // 5. Batch tracing
            var sequenceLayers = interpolationPointLayers.ToDictionary(ci => ci.Key, ci => new Layer <SequencePath>
            {
                Paths = ci.Value.Paths.Select(path => new SequencePath
                {
                    Path      = path,
                    Sequences = Sequencing.Create(path.Points.Select(p => p.Direction).ToList()).ToList()
                }).ToList()
            });

            var segmentLayers = sequenceLayers.ToDictionary(ci => ci.Key, ci => new Layer <SegmentPath>
            {
                Paths = ci.Value.Paths.Select(path => new SegmentPath
                {
                    Segments = path.Sequences.Select(s => Segmentation.Fit(path.Path.Points, s, tracing, rendering)).SelectMany(s => s).ToList()
                }).ToList()
            });

            return(new TracedImage(segmentLayers, image.Width, image.Height));
        }
        // 5.4. Fit a quadratic spline through this point, measure errors on every point in the sequence
        // helpers and projecting to get control point
        public static Segment Fit(IReadOnlyList <InterpolationPoint> path, double threshold, SequenceIndices sequence, int sequenceLength, ref int errorIndex, SvgRendering rendering)
        {
            var startPoint = path[sequence.Start];
            var endPoint   = path[sequence.End];
            var fitPoint   = path[errorIndex];

            Func <int, double> pseudoIndexCalc = i => (i - sequence.Start) / (double)sequenceLength;
            var midPoint = CreateSplinePoint(pseudoIndexCalc(errorIndex), startPoint, endPoint, fitPoint, true);

            // Check every point
            var isSpline = Fit(i => path[i], i => CreateSplinePoint(pseudoIndexCalc(i), startPoint, midPoint, endPoint), threshold,
                               sequence.Start + 1, i => i != sequence.End, i => (i + 1) % path.Count, ref errorIndex);

            return(isSpline ? new SplineSegment {
                Start = startPoint, Mid = midPoint, End = endPoint, Radius = rendering.QCpr, RoundDecimalPlaces = rendering.RoundCoords
            } : null);
        }
Exemple #4
0
        // 5.2. Fit a straight line on the sequence
        public static Segment Fit(IReadOnlyList <InterpolationPoint> path, double threshold, SequenceIndices sequence, int sequenceLength, out int errorIndex, SvgRendering rendering)
        {
            var startPoint   = path[sequence.Start];
            var endPoint     = path[sequence.End];
            var partialPoint = CreateLinePoint(sequenceLength, startPoint, endPoint, true);

            var pathLength = path.Count;
            Func <int, double> pseudoIndexCalc = i =>
            {
                // I don't know what 'pl' as a variable name means. Is it related to path length?
                var pl = i - sequence.Start;
                pl += pl < 0 ? pathLength : 0;
                return(pl);
            };

            errorIndex = sequence.Start;
            var isLine = Fit(i => path[i], i => CreateLinePoint(pseudoIndexCalc(i), startPoint, partialPoint), threshold,
                             (sequence.Start + 1) % pathLength, i => i != sequence.End, i => (i + 1) % pathLength, ref errorIndex);

            return(isLine ? new LineSegment {
                Start = startPoint, End = endPoint, Radius = rendering.LCpr, RoundDecimalPlaces = rendering.RoundCoords
            } : null);
        }
        // 5.2. - 5.6. recursively fitting a straight or quadratic line segment on this sequence of path nodes,
        // called from tracepath()
        // Returns a segment (a list of those doubles is a segment).
        public static IEnumerable <Segment> Fit(IReadOnlyList <InterpolationPoint> path, SequenceIndices sequence, Tracing tracing, SvgRendering rendering)
        {
            var pathLength = path.Count;

            // return if invalid sequence.End
            // TODO: When would this ever happen?
            if ((sequence.End > pathLength) || (sequence.End < 0))
            {
                yield break;
            }

            // TODO: This is actually the number of line segments in the sequence. Not the number of points in the sequence.
            var sequenceLength = sequence.End - sequence.Start;

            sequenceLength += sequenceLength < 0 ? pathLength : 0;

            int errorIndex;
            var lineResult = LineSegment.Fit(path, tracing.LTres, sequence, sequenceLength, out errorIndex, rendering);

            if (lineResult != null)
            {
                yield return(lineResult);

                yield break;
            }

            // 5.3. If the straight line fails (an error>ltreshold), find the point with the biggest error
            var fitIndex     = errorIndex;
            var splineResult = SplineSegment.Fit(path, tracing.QTres, sequence, sequenceLength, ref errorIndex, rendering);

            if (splineResult != null)
            {
                yield return(splineResult);

                yield break;
            }

            // 5.5. If the spline fails (an error>qtreshold), find the point with the biggest error,
            var splitIndex = (fitIndex + errorIndex) / 2;

            // 5.6. Split sequence and recursively apply 5.2. - 5.6. to startpoint-splitpoint and splitpoint-endpoint sequences
            foreach (var segmentPart in Fit(path, new SequenceIndices {
                Start = sequence.Start, End = splitIndex
            }, tracing, rendering))
            {
                yield return(segmentPart);
            }
            foreach (var segmentPart in Fit(path, new SequenceIndices {
                Start = splitIndex, End = sequence.End
            }, tracing, rendering))
            {
                yield return(segmentPart);
            }
        }