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); }
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)); }