Example #1
0
        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());
        }
Example #2
0
        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);
        }