public static Point2D QuadraticBezierEnvelope0(
            Point2D point,
            Rectangle2D bounds,
            Point2D topLeft, Point2D topHandle, Point2D topRight, Point2D rightHandle,
            Point2D bottomRight, Point2D bottomHandle, Point2D bottomLeft, Point2D leftHandle)
        {
            // topLeft                             topRight
            //   0------------------0------------------0
            //   |              topHandle              |
            //   |                                     |
            //   |                                     |
            //   |                                     |
            //   |                                     |
            //   0 leftHandle              rightHandle 0
            //   |                                     |
            //   |                                     |
            //   |                                     |
            //   |                                     |
            //   |             bottomHandle            |
            //   0------------------0------------------0
            // bottomLeft                       bottomRight
            //
            // Install "Match Margin" Extension to enable word match highlighting, to help visualize where a variable resides in the ASCI map.

            var normal      = (X : (point.X - bounds.X) / bounds.Width, Y : (point.Y - bounds.Top) / bounds.Height);
            var leftAnchor  = InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(normal.Y, topLeft.X, topLeft.Y, leftHandle.X, leftHandle.Y, bottomLeft.X, bottomLeft.Y);
            var handle      = InterpolateLinear2DTests.LinearInterpolate2D(normal.Y, topHandle.X, topHandle.Y, bottomHandle.X, bottomHandle.Y);
            var rightAnchor = InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(normal.Y, topRight.X, topRight.Y, rightHandle.X, rightHandle.Y, bottomRight.X, bottomRight.Y);

            return(new Point2D(InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(normal.X, leftAnchor.X, leftAnchor.Y, handle.X, handle.Y, rightAnchor.X, rightAnchor.Y)));
        }
        public static double QuadraticBezierArcLengthBySegments(
            double ax, double ay,
            double bx, double by,
            double cx, double cy)
        {
            var length = 0d;
            var p      = InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(0, ax, ay, bx, by, cx, cy);
            var prevX  = p.X;
            var prevY  = p.Y;

            for (var t = 0.005; t <= 1.0; t += 0.005)
            {
                p = InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(t, ay, ax, by, bx, cx, cy);
                var deltaX = p.X - prevX;
                var deltaY = p.Y - prevY;
                length += Sqrt((deltaX * deltaX) + (deltaY * deltaY));

                prevX = p.X;
                prevY = p.Y;
            }

            // Exercise:  due to roundoff, it's possible to miss a small segment at the end.  how to compensate??
            return(length);
        }
        public static (Point2D, double) FindNearestPoint(double aX, double aY, double bX, double bY, double cX, double cY, double x, double y)
        {
            var(a, b, c, d) = GetCubicPolynomialFromQuadraticBezierAndPointTests.GetCubicPolynomialFromQuadraticBezierAndPoint(aX, aY, bX, bY, cX, cY, x, y);
            var candidates = FindAllRealRootsInIntervalTests.FindAllRootsInInterval(0d, 1d, a, b, c, d);

            // Find the candidate that yields the closest point on the bezier to the given point.
            var t           = double.NaN;
            var output      = (double.NaN, double.NaN);
            var minDistance = double.MaxValue;

            foreach (var candidate in candidates)
            {
                var ptAtCandidate = InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(candidate, aX, aY, bX, bY, cX, cY);
                var distance      = SquareDistanceTests.SquareDistance(ptAtCandidate.X, ptAtCandidate.Y, x, y);
                if (distance < minDistance)
                {
                    minDistance = distance;
                    t           = candidate;
                    output      = ptAtCandidate;
                }
            }

            return(output, t);
        }
Example #4
0
        public static Rectangle2D QuadraticBezierBounds0(
            double ax, double ay,
            double bx, double by,
            double cx, double cy)
        {
            var sortOfCloseLength = QuadraticBezierSegmentLengthTests.QuadraticBezierArcLength(ax, ay, bx, by, cx, cy);

            // ToDo: Need to make this more efficient. Don't need to rebuild the point array every time.
            var points = new List <(double X, double Y)>(FunctionalInterpolationTests.Interpolate0to1((int)(sortOfCloseLength / 3), (i) => InterpolateBezierQuadratic2DTests.QuadraticBezierInterpolate2D(i, ax, ay, bx, by, cx, cy)));

            var left   = points[0].X;
            var top    = points[0].Y;
            var right  = points[0].X;
            var bottom = points[0].Y;

            foreach (var(X, Y) in points)
            {
                // ToDo: Measure performance impact of overwriting each time.
                left   = X <= left ? X : left;
                top    = Y <= top ? Y : top;
                right  = X >= right ? X : right;
                bottom = Y >= bottom ? Y : bottom;
            }

            return(Rectangle2D.FromLTRB(left, top, right, bottom));
        }