public BezierSubdivision Prev() // Previous index at current level { var next = new BezierSubdivision(new List <Vector2>(Points), Level, Index - 1); next.ScaleRight(-1); next.Reverse(); return(next); }
public BezierSubdivision Parent() // Parent subdivision (inverse of BezierSubdivide) { var parent = new BezierSubdivision(new List <Vector2>(Points), Level - 1, Index >> 1); if ((Index & 1) == 0) { parent.ScaleRight(2); } else { parent.ScaleLeft(-1); } return(parent); }
public static List <Vector2> MoveAnchorsToLength(List <Vector2> anchors, PathType pathType, double newLength, out PathType newPathType) { var newAnchors = new List <Vector2>(); var sliderPath = new SliderPath(pathType, anchors.ToArray(), newLength); var maxSliderPath = new SliderPath(pathType, anchors.ToArray()); if (newLength > maxSliderPath.Distance) { // Extend linearly switch (pathType) { case PathType.Bezier: newPathType = PathType.Bezier; newAnchors.AddRange(anchors); if (newAnchors.Count > 1 && newAnchors[newAnchors.Count - 2] == newAnchors[newAnchors.Count - 1]) { newAnchors[newAnchors.Count - 2] = newAnchors[newAnchors.Count - 2] + Vector2.UnitX; } newAnchors.Add(anchors.Last()); newAnchors.Add(sliderPath.PositionAt(1)); break; case PathType.Catmull: case PathType.PerfectCurve: // Convert to bezier and then extend newPathType = PathType.Bezier; newAnchors = BezierConverter.ConvertToBezier(sliderPath).ControlPoints; newAnchors.Add(anchors.Last()); newAnchors.Add(sliderPath.PositionAt(1)); break; default: newPathType = pathType; newAnchors.AddRange(anchors); newAnchors[newAnchors.Count - 1] = sliderPath.PositionAt(1); break; } } else { switch (sliderPath.Type) { case PathType.Catmull: case PathType.Bezier: newPathType = PathType.Bezier; // Convert in case the path type is catmull var convert = BezierConverter.ConvertToBezier(sliderPath).ControlPoints; // Find the last bezier segment and the pixel length at that part BezierSubdivision subdivision = null; double totalLength = 0; foreach (var bezierSubdivision in ChopAnchors(convert)) { subdivision = bezierSubdivision; var length = bezierSubdivision.SubdividedApproximationLength(); if (totalLength + length > newLength) { break; } totalLength += length; newAnchors.AddRange(bezierSubdivision.Points); } if (subdivision == null) { break; } // Find T for the remaining pixel length var t = subdivision.LengthToT(newLength - totalLength); // ScaleRight the BezierSubdivision so the anchors end at T subdivision.ScaleRight(t); // Add the scaled anchors newAnchors.AddRange(subdivision.Points); break; case PathType.PerfectCurve: newPathType = PathType.PerfectCurve; newAnchors.AddRange(anchors); newAnchors[1] = sliderPath.PositionAt(0.5); newAnchors[2] = sliderPath.PositionAt(1); break; default: newPathType = pathType; if (anchors.Count > 2) { // Find the section of the linear slider which contains the slider end totalLength = 0; foreach (var bezierSubdivision in ChopAnchorsLinear(anchors)) { newAnchors.Add(bezierSubdivision.Points[0]); var length = bezierSubdivision.Length(); if (totalLength + length > newLength) { break; } totalLength += length; } newAnchors.Add(sliderPath.PositionAt(1)); } else { newAnchors.AddRange(anchors); newAnchors[newAnchors.Count - 1] = sliderPath.PositionAt(1); } break; } } return(newAnchors); }