一本免费的在线书籍,供你在非常需要了解如何处理贝塞尔相关的事情。
https://pomax.github.io/bezierinfo/zh-CN/index.html
An algorithm to find bounding box of closed bezier curves? - Stack Overflow
https://stackoverflow.com/questions/2587751/an-algorithm-to-find-bounding-box-of-closed-bezier-curves
前端动画之贝塞尔曲线推导及应用-CSDN博客
https://blog.csdn.net/frontend_frank/article/details/123437040
贝塞尔曲线在线绘制🚀
https://www.bezier-curve.com/
Calculating / Computing the Bounding Box of Cubic Bezier https://floris.briolas.nl/floris/2009/10/bounding-box-of-cubic-bezier/
获取三阶贝塞尔曲线的最小包围盒
c# https://floris.briolas.nl/floris/2009/10/bounding-box-of-cubic-bezier/
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace BoundingBoxTestProject
{
public static class BezierOp
{
public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
//cubic polinomal
//x = At^3 + Bt^2 + Ct + D
//where A,B,C,D:
//A = p3 -3 * p2 + 3 * p1 - p0
//B = 3 * p2 - 6 * p1 +3 * p0
//C = 3 * p1 - 3 * p0
//D = p0
public static Func<double, double, double, double, double, double> bezierSpline = (p0, p1, p2, p3, t) =>
(p3 - 3 * p2 + 3 * p1 - p0) * Math.Pow(t, 3)
+ (3 * p2 - 6 * p1 + 3 * p0) * Math.Pow(t, 2)
+ (3 * p1 - 3 * p0) * t
+ (p0);
//X = At^3 + Bt^2 + Ct + D
//where A,B,C,D:
//A = (p3 -3 * p2 + 3 * p1 - p0)
//B = (3 * p2 - 6 * p1 +3 * p0)
//C = (3 * p1 - 3 * p0)
//D = (p0)
//We would like to know the values of t where X = 0
//X = (p3-3*p2+3*p1-p0)t^3 + (3*p2-6*p1+3*p0)t^2 + (3*p1-3*p0)t + (p0)
//Derivetive :
//X' = 3(p3-3*p2+3*p1-p0)t^(3-1) + 2(6*p2-12*p1+6*p0)t^(2-1) + 1(3*p1-3*p0)t^(1-1) [f(x)=aX^n => f'(x)=a*n*X^(n-1) remember?]
//simplified:
//X' = (3*p3-9*p2+9*p1-3*p0)t^2 + (6*p2-12*p1+6*p0)t + (3*p1-3*p0)
//**!!reusing a,b,and c!!!***
//taken as aX^2 + bX + c a,b and c are:
public static Func<double, double, double, double, double> A = (p0, p1, p2, p3) => 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0;
//ommitting power 2 for now
public static Func<double, double, double, double> B = (p0, p1, p2) => 6 * p2 - 12 * p1 + 6 * p0;
public static Func<double, double, double> C = (p0, p1) => 3 * p1 - 3 * p0;
//b^2 - 4ac = Determinant
public static Func<double, double, double, double> Determinant = (a, b, c) => Math.Pow(b, 2) - 4d * a * c;
public static Func<double, double, double, double[]> Solve = (a, b, c) =>
{
Func<double, double, double, bool, double> _Solve =
(a_, b_, c_, s) =>
(-b_ +
(Math.Sqrt((b_ * b_) - (4d * a_ * c_)) *
((s) ? 1d : -1d))) / (2d * a_);
double d = Determinant(a, b, c);
if (d < 0)
return new double[] { };
if (a == 0)
//aX^2 + bX + c well then then this is a simple line
//x= -c / b
return new double[] { -c / b };
if (d == 0)
{
return new double[] { _Solve(a, b, c, true) };
}
else
return new double[]
{
_Solve(a, b, c, true),
_Solve(a, b, c, false)
};
};
public static RectangleF GetRect(PointF p1, PointF c1, PointF c2, PointF p2)
{
double aX = A(p1.X, c1.X, c2.X, p2.X);
double bX = B(p1.X, c1.X, c2.X);
double cX = C(p1.X, c1.X);
double aY = A(p1.Y, c1.Y, c2.Y, p2.Y);
double bY = B(p1.Y, c1.Y, c2.Y);
double cY = C(p1.Y, c1.Y);
var resX = Solve(aX, bX, cX).Where(t => (t >= 0) && (t <= 1)); //solve for t ==0 & filter
var resY = Solve(aY, bY, cY).Where(t => (t >= 0) && (t <= 1)); //solve for t ==0 & filter
//Draw min and max;
List<PointF> _BBox = new List<PointF>();
_BBox.Add(p1); //Add Begin and end point not the control points!
_BBox.Add(p2);
foreach (var e in resX.Union(resY))
{
double x = bezierSpline(p1.X, c1.X, c2.X, p2.X, e);
double y = bezierSpline(p1.Y, c1.Y, c2.Y, p2.Y, e);
PointF p = new PointF((float)x, (float)y);
_BBox.Add(p);
}
float minX = float.MaxValue;
float minY = float.MaxValue;
float maxX = float.MinValue;
float maxY = float.MinValue;
foreach (var e in _BBox) //find the bounding box.
{
minX = Math.Min(e.X, minX);
minY = Math.Min(e.Y, minY);
maxX = Math.Max(e.X, maxX);
maxY = Math.Max(e.Y, maxY);
}
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
}
}
c++ 由上述c#代码改写而来,未做优化
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
// 表示一个边界框的结构体
struct BoundingBox {
double x; // 左上角 x 坐标
double y; // 左上角 y 坐标
double width; // 宽度
double height; // 高度
BoundingBox(double _x, double _y, double _width, double _height) :
x(_x), y(_y), width(_width), height(_height) {}
};
// 表示一个二维点的结构体
struct Point {
double x; // x 坐标
double y; // y 坐标
Point(double _x, double _y) : x(_x), y(_y) {}
};
// 计算三次贝塞尔曲线的值
double bezierSpline(double p0, double p1, double p2, double p3, double t) {
double mt = 1 - t;
return mt * mt * mt * p0 + 3 * mt * mt * t * p1 + 3 * mt * t * t * p2 + t * t * t * p3;
}
// 计算贝塞尔曲线的导数系数
void calculateCoefficients(double p0, double p1, double p2, double p3, double &a, double &b, double &c) {
a = 3 * (p3 - 3 * p2 + 3 * p1 - p0);
b = 6 * (p2 - 2 * p1 + p0);
c = 3 * (p1 - p0);
}
// 解二次方程 ax^2 + bx + c = 0,并返回在区间 [0, 1] 内的实数解
std::vector<double> solveQuadratic(double a, double b, double c) {
std::vector<double> solutions;
// 计算判别式
double discriminant = b * b - 4 * a * c;
if (discriminant >= 0) {
double sqrtDiscriminant = std::sqrt(discriminant);
double t1 = (-b + sqrtDiscriminant) / (2 * a);
double t2 = (-b - sqrtDiscriminant) / (2 * a);
if (t1 >= 0 && t1 <= 1) {
solutions.push_back(t1);
}
if (t2 >= 0 && t2 <= 1) {
solutions.push_back(t2);
}
}
return solutions;
}
// 计算贝塞尔曲线的边界框
BoundingBox getBoundsOfCurve(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) {
double aX, bX, cX, aY, bY, cY;
// 计算 x 和 y 方向的导数系数
calculateCoefficients(x0, x1, x2, x3, aX, bX, cX);
calculateCoefficients(y0, y1, y2, y3, aY, bY, cY);
// 找到导数为零的参数值
std::vector<double> xSolutions = solveQuadratic(aX, bX, cX);
std::vector<double> ySolutions = solveQuadratic(aY, bY, cY);
// 存储边界框的点
std::vector<Point> bboxPoints;
bboxPoints.push_back(Point(x0, y0));
bboxPoints.push_back(Point(x3, y3));
// 在导数为零的参数值下计算曲线上的点
for (double t : xSolutions) {
double x = bezierSpline(x0, x1, x2, x3, t);
double y = bezierSpline(y0, y1, y2, y3, t);
bboxPoints.push_back(Point(x, y));
}
for (double t : ySolutions) {
double x = bezierSpline(x0, x1, x2, x3, t);
double y = bezierSpline(y0, y1, y2, y3, t);
bboxPoints.push_back(Point(x, y));
}
// 计算边界框的坐标
double minX = bboxPoints[0].x;
double minY = bboxPoints[0].y;
double maxX = bboxPoints[0].x;
double maxY = bboxPoints[0].y;
for (const Point &point : bboxPoints) {
minX = std::min(minX, point.x);
minY = std::min(minY, point.y);
maxX = std::max(maxX, point.x);
maxY = std::max(maxY, point.y);
}
// 创建边界框并返回
return BoundingBox(minX, minY, maxX - minX, maxY - minY);
}
int main()
{
// 定义四个控制点的坐标
// double x0 = 300.0, y0 = 400.0, x1 = 400.0, y1 = 300.0, x2 = 700.0, y2 = 500.0, x3 = 500.0, y3 = 500.0;
double x0 = 300.0, y0 = 400.0, x1 = 400.0, y1 = 600.0, x2 = 700.0, y2 = 500.0, x3 = 500.0, y3 = 500.0;
// 计算贝塞尔曲线的边界框
BoundingBox bounds = getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3);
std::cout << "Bounding Box: (" << bounds.x << ", " << bounds.y << ") - Width: " << bounds.width << ", Height: " << bounds.height;
return 0;
}
// Bounding Box: (300, 400) - Width: 267.277, Height: 125