贝塞尔曲线的一些资料收集

贝塞尔曲线的一些资料收集_第1张图片
一本免费的在线书籍,供你在非常需要了解如何处理贝塞尔相关的事情。
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/

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#代码改写而来,未做优化

#include 
#include 
#include 
#include 

// 表示一个边界框的结构体
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

你可能感兴趣的:(算法)