static List <Curve2DSample> _computeSamples(List <Offset> controlPoints, float?tension) { List <Offset> _controlPoints = new List <Offset>(); _controlPoints.Add(Offset.zero); _controlPoints.AddRange(controlPoints); _controlPoints.Add(new Offset(1.0f, 1.0f)); return(CatmullRomSpline.precompute(_controlPoints, tension: tension).generateSamples( start: 0.0f, end: 1.0f, tolerance: 1e-12f).ToList()); }
static bool validateControlPoints( List <Offset> controlPoints, float?tension = 0.0f, List <string> reasons = null) { D.assert(tension != null); if (controlPoints == null) { D.assert(() => { reasons?.Add("Supplied control points cannot be null"); return(true); }); return(false); } if (controlPoints.Count < 2) { D.assert(() => { reasons?.Add("There must be at least two points supplied to create a valid curve."); return(true); }); return(false); } List <Offset> _controlPoints = new List <Offset>(); _controlPoints.AddRange(controlPoints); _controlPoints.Insert(0, Offset.zero); _controlPoints.Add(new Offset(1.0f, 1.0f)); Offset startHandle = _controlPoints[0] * 2.0f - _controlPoints[1]; Offset endHandle = _controlPoints.last() * 2.0f - _controlPoints[_controlPoints.Count - 2]; _controlPoints.Insert(0, startHandle); _controlPoints.Add(endHandle); float lastX = -float.PositiveInfinity; for (int i = 0; i < _controlPoints.Count; ++i) { if (i > 1 && i < _controlPoints.Count - 2 && (_controlPoints[i].dx <= 0.0f || _controlPoints[i].dx >= 1.0f)) { D.assert(() => { reasons?.Add("Control points must have X values between 0.0 and 1.0, exclusive. " + $"Point {i} has an x value ({_controlPoints[i].dx}) which is outside the range."); return(true); }); return(false); } if (_controlPoints[i].dx <= lastX) { D.assert(() => { reasons?.Add("Each X coordinate must be greater than the preceding X coordinate " + $"(i.e. must be monotonically increasing in X). Point {i} has an x value of " + $"{_controlPoints[i].dx}, which is not greater than {lastX}"); return(true); }); return(false); } lastX = _controlPoints[i].dx; } bool success = true; lastX = -float.PositiveInfinity; const float tolerance = 1e-3f; CatmullRomSpline testSpline = new CatmullRomSpline(_controlPoints, tension: tension); float start = testSpline.findInverse(0.0f); float end = testSpline.findInverse(1.0f); IEnumerable <Curve2DSample> samplePoints = testSpline.generateSamples(start: start, end: end); if (samplePoints.First().value.dy.abs() > tolerance || (1.0f - samplePoints.Last().value.dy).abs() > tolerance) { bool bail = true; success = false; D.assert(() => { reasons?.Add($"The curve has more than one Y value at X = {samplePoints.First().value.dx}. " + "Try moving some control points further away from this value of X, or increasing " + "the tension."); bail = reasons == null; return(true); }); if (bail) { return(false); } } foreach (Curve2DSample sample in samplePoints) { Offset point = sample.value; float t = sample.t; float x = point.dx; if (t >= start && t <= end && (x < -1e-3f || x > 1.0f + 1e-3f)) { bool bail = true; success = false; D.assert(() => { reasons?.Add($"The resulting curve has an X value ({x}) which is outside " + "the range [0.0, 1.0], inclusive."); bail = reasons == null; return(true); }); if (bail) { return(false); } } if (x < lastX) { bool bail = true; success = false; D.assert(() => { reasons?.Add($"The curve has more than one Y value at x = {x}. Try moving " + "some control points further apart in X, or increasing the tension."); bail = reasons == null; return(true); }); if (bail) { return(false); } } lastX = x; } return(success); }