|
路径追踪算法,贝塞尔曲线,分直线,二阶贝塞尔,三阶贝塞尔- #include <stdio.h>
- #include <math.h>
- // 二维坐标结构体
- typedef struct {
- double x; // X坐标值
- double y; // Y坐标值
- } Point;
- // 二维向量结构体
- typedef struct {
- double dx; // X分量
- double dy; // Y分量
- } Vector;
- // 计算两点之间的距离
- // p1: 第一个点
- // p2: 第二个点
- double distance(Point p1, Point p2) {
- double dx = p2.x - p1.x;
- double dy = p2.y - p1.y;
- return sqrt(dx*dx + dy*dy);
- }
- // 计算二阶贝塞尔曲线上的点
- // p0: 起始点
- // p1: 控制点
- // p2: 终点
- // t: 参数值,[0, 1]范围内的值
- Point calculateQuadraticBezier(Point p0, Point p1, Point p2, double t) {
- double u = 1 - t;
- double tt = t * t;
- double uu = u * u;
- double ut = u * t;
- Point p;
- p.x = uu * p0.x + 2 * ut * p1.x + tt * p2.x; // 二阶贝塞尔曲线的x坐标计算公式
- p.y = uu * p0.y + 2 * ut * p1.y + tt * p2.y; // 二阶贝塞尔曲线的y坐标计算公式
- return p;
- }
- // 计算三阶贝塞尔曲线上的点
- // p0: 起始点
- // p1: 控制点1
- // p2: 控制点2
- // p3: 终点
- // t: 参数值,[0, 1]范围内的值
- Point calculateCubicBezier(Point p0, Point p1, Point p2, Point p3, double t) {
- double u = 1 - t;
- double tt = t * t;
- double uu = u * u;
- double ut = u * t;
- Point p;
- p.x = uu * u * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + tt * t * p3.x; // 三阶贝塞尔曲线的x坐标计算公式
- p.y = uu * u * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + tt * t * p3.y; // 三阶贝塞尔曲线的y坐标计算公式
- return p;
- }
- int main() {
- // 示例用法
- Point p0 = {0, 0}; // 起始点
- Point p1 = {1, 2}; // 控制点1
- Point p2 = {3, 4}; // 控制点2
- Point p3 = {5, 6}; // 终点
- int numSteps = 10; // 贝塞尔曲线上的点数
- Vector tangent; // 切线向量
- double t; // 时间参数
- for (int i = 0; i <= numSteps; i++) {
- t = (double)i / numSteps;
- // 计算二阶贝塞尔曲线上的点
- Point point = calculateQuadraticBezier(p0, p1, p2, t);
- // 计算切线向量
- Vector v;
- v.dx = 2 * (p1.x - p0.x) * (1 - t) + 2 * (p2.x - p1.x) * t; // 切线向量的x分量计算公式
- v.dy = 2 * (p1.y - p0.y) * (1 - t) + 2 * (p2.y - p1.y) * t; // 切线向量的y分量计算公式
- // 将切线向量单位化
- double length = sqrt(v.dx * v.dx + v.dy * v.dy); // 计算切线向量的模长度
- // 通过平方和的开方计算切线向量的模。
- // 切线向量的模表示向量的长度。
- // 使用勾股定理将x和y分量的平方和开方,得到向量的长度。
- tangent.dx = v.dx / length; // 单位化后的切线向量的x分量
- tangent.dy = v.dy / length; // 单位化后的切线向量的y分量
- // 计算预览点的位置
- Point previewPoint;
- previewPoint.x = point.x + tangent.dx; // 预览点的x坐标
- previewPoint.y = point.y + tangent.dy; // 预览点的y坐标
- printf("Point %d: (%.2lf, %.2lf)\n", i, previewPoint.x, previewPoint.y);
- }
- return 0;
- }
- 参数值 `t` 是一个范围在 [0, 1] 内的值,用于控制贝塞尔曲线上的点的位置。
- 在贝塞尔曲线的定义中,我们使用控制点来塑造曲线的形状。贝塞尔曲线的起始点和终点是通过调整参数 `t` 来确定的。当 `t` 的值为 0 时,表示我们取贝塞尔曲线上的起始点;当 `t` 的值为 1 时,表示我们取贝塞尔曲线上的终点。
- 当 `t` 的值在 (0, 1) 的范围内时,我们可以根据具体的数值来确定贝塞尔曲线上的中间点的位置。较小的 `t` 值会使我们更靠近起始点,而较大的 `t` 值会使我们更接近终点。在 (0, 1) 范围内,我们可以通过调整 `t` 的值来获得沿着贝塞尔曲线平滑变化的点的位置。
- 需要注意的是,贝塞尔曲线上的点并不一定要在参数 `t` 等于整数值时才存在。实际上,我们可以使用更多的小数值来控制曲线上的更多点的位置,以获得更精细的曲线形状。通过在 [0, 1] 范围内对 `t` 的连续变化,我们可以生成贝塞尔曲线上的连续点集,从而绘制出平滑曲线形状。
- 总之,参数值 `t` 表示在贝塞尔曲线上选择点的位置,范围在 [0, 1] 内,可以通过调整 `t` 的大小来控制点在曲线上的位置和移动的路径。
复制代码 这个程序中,我们首先定义了一个二维坐标结构体Point和一个二维向量结构体Vector。然后我们实现了计算两点之间距离的函数distance,计算二阶贝塞尔曲线上的点的函数calculateQuadraticBezier,以及计算三阶贝塞尔曲线上的点的函数calculateCubicBezier。
在main函数中,我们先定义了起始点p0、控制点1p1、控制点2p2和终点p3。然后定义了一个整型变量numSteps,表示贝塞尔曲线上的点数。接下来,我们定义了一个切线向量Vector和一个时间参数t。
在for循环中,我们根据参数t的值,通过调用calculateQuadraticBezier函数计算出贝塞尔曲线上的点point。然后,我们根据贝塞尔曲线的性质计算切线向量v,并将其单位化得到Vector类型的切线向量tangent。最后,根据切线向量和贝塞尔曲线上的点,计算预览点的位置previewPoint。
程序以格式化输出的方式打印出每个预览点的坐标信息。
最后,返回0表示程序正常结束。
|
|