private static void Subdivide(List <SKPoint> path, int desiredPointCount) { var desiredLength = path.Count + desiredPointCount; var step = SKGeometry.Perimeter(path) / desiredPointCount; var i = 0; var cursor = 0.0f; var insertAt = step / 2f; while (path.Count < desiredLength) { var a = path[i]; var b = path[(i + 1) % path.Count]; var segment = SKGeometry.Distance(a, b); if (insertAt <= cursor + segment) { path.Insert(i + 1, segment != 0 ? SKGeometry.PointAlong(a, b, (insertAt - cursor) / segment) : a); insertAt += step; continue; } cursor += segment; i++; } }
private static void Rotate(List <SKPoint> from, List <SKPoint> to) { var bestOffset = 0; var min = float.PositiveInfinity; var len = from.Count; for (var offset = 0; offset < len; offset++) { var sumOfSquares = 0.0f; for (var i = 0; i < len; i++) { var d = SKGeometry.Distance(from[(offset + i) % len], to[i]); sumOfSquares += d * d; } if (sumOfSquares < min) { min = sumOfSquares; bestOffset = offset; } } if (bestOffset != 0) { Rotate(from, bestOffset); } }
private static void Bisect(List <SKPoint> ring, float maxSegmentLength) { // skip if we have asked that the path not be bisected if (maxSegmentLength <= 0) { return; } for (var i = 0; i < ring.Count; i++) { var a = ring[i]; var b = i == ring.Count - 1 ? ring[0] : ring[i + 1]; // could splice the whole set for a segment instead, but a bit messy while (SKGeometry.Distance(a, b) > maxSegmentLength) { b = SKGeometry.PointAlong(a, b, 0.5f); ring.Insert(i + 1, b); } } }
private static List <SKPoint> NormalizePath(SKPath parsed, float maxSegmentLength) { var skipBisect = false; var points = CreateLinearPathPoints(parsed); if (points == null) { points = CreateCurvedPathPoints(parsed, maxSegmentLength); skipBisect = true; } // TODO: //// no duplicate closing point for now //if (points.Count > 1 && SKGeometry.Distance(points[0], points[points.Count - 1]) < 1e-9f) //{ // points.pop(); //} // 3+ points to make a polygon if (points.Count < 3) { return(null); } // make all rings clockwise if (SKGeometry.Area(points) > 0) { points.Reverse(); } if (!skipBisect && maxSegmentLength > 0) { Bisect(points, maxSegmentLength); } return(points); }