程序功能:给定平面上15个不同的点(数据文件输入) ,用de Boor分割算法编程生成平面三次B样条曲线。
程序语言:c++
程序说明:
这段程序是一个用于绘制B样条曲线的图形应用程序。下面是对程序各部分的功能进行说明:
- 头文件引入:程序使用了一些头文件,包括iostream、fstream、vector、cmath和graphics.h等。
- Point类:这个类表示一个点,具有x和y坐标属性。
- BSplineCurve类:这个类表示B样条曲线,包括控制点、结点向量和曲线次数等属性。
- control_points:控制点的向量,存储了所有控制点的坐标。
- knot_vector:结点向量,根据控制点数量和曲线次数生成。
- degree:曲线的次数。 构造函数:初始化控制点和结点向量。
- BasisFunction()函数:计算基函数的值。
- CalculatePoint()函数:计算B样条曲线上的点。
- drawLine()函数:绘制一条直线。
- main()函数:程序的主函数,包含了读取控制点、初始化图形窗口、绘制控制多边形和B样条曲线等过程。
- 从文件中读取控制点的坐标。
- 初始化图形窗口。
- 绘制控制多边形。
- 创建BSplineCurve对象。
- 根据步长循环计算并绘制B样条曲线上的点,并连接相邻点。
- 按下任意键关闭图形窗口。
程序代码:
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <graphics.h>
#include <conio.h>
using namespace std;
class Point
{
public:
float x, y;
Point(float x = 0, float y = 0) : x(x), y(y) {}
};
class BSplineCurve
{
public:
vector<pair<float, float>> control_points; // 控制点
vector<float> knot_vector; // 结点向量
int degree; // 曲线次数
//Constructor
BSplineCurve(vector<pair<float, float>> points, int k)
{
control_points = points;
degree = k;
// 初始化结点向量, m = n + k + 1 ,m节点数量, n控制点数量 ,k 次数
for (int i = 0; i <= control_points.size() + degree; i++)
{
if (i < degree)
{
knot_vector.push_back(0);
}
else if (i < control_points.size())
{
knot_vector.push_back((i - degree) / (float)(control_points.size() - degree));
}
else
{
knot_vector.push_back(1);
}
}
}
// 计算基函数值
float BasisFunction(int i, int k, float u)
{
if (k == 0)
{
if (u >= knot_vector[i] && u < knot_vector[i + 1])
{
return 1;
}
else
{
return 0;
}
}
float a = 0, b = 0;
if (knot_vector[i + k] - knot_vector[i] != 0)
{
a = (u - knot_vector[i]) / float(knot_vector[i + k] - knot_vector[i]);
}
if (knot_vector[i + k + 1] - knot_vector[i + 1] != 0)
{
b = (knot_vector[i + k + 1] - u) / float(knot_vector[i + k + 1] - knot_vector[i + 1]);
}
return a * BasisFunction(i, k - 1, u) + b * BasisFunction(i + 1, k - 1, u);
}
// 计算B 样条曲线上的点
Point CalculatePoint(float u)
{
Point res(0,0);
for (int i = 0; i < control_points.size(); ++i)
{
float basis = BasisFunction(i, degree, u);
res.x += control_points[i].first * basis;
res.y += control_points[i].second * basis;
}
return res;
}
};
void drawLine(int x1, int y1, int x2, int y2, int color)
{
setcolor(color);
line(x1, y1, x2, y2);
}
int main()
{
ifstream infile("F:/Program/CG_HM6/points.txt");
if (!infile)
{
cout << "无法打开文件!" << endl;
return 1;
}
vector<pair<float, float>> control_points; // 存储控制点
float x, y;
while (infile >> x >> y)
{
control_points.push_back(make_pair(x, y));
}
infile.close();
initgraph(800, 800);
// 绘制控制多边形
for (size_t i = 0; i < control_points.size() - 1; ++i)
{
drawLine(control_points[i].first, control_points[i].second, control_points[i + 1].first, control_points[i + 1].second, GREEN);
}
int degree = 3; // 曲线次数
BSplineCurve curve(control_points, degree);
const float step = 0.005; // 步长
Point p0 = curve.CalculatePoint(0);
for (float u = 0; u <= 1; u += step)
{
Point p1 = curve.CalculatePoint(u);
if (p0.x != 0 || p0.y != 0)
{
drawLine(p0.x, p0.y, p1.x, p1.y, WHITE);
//cout << p0.x << '\t' << p0.y << endl;
}
p0 = p1;
// 判断是否为最后一个控制点
if (u + step > 1 && u < 1)
{
Point p2 = curve.CalculatePoint(1-0.001);
drawLine(p1.x, p1.y, p2.x, p2.y, WHITE);
}
}
cout << "按下任意键关闭图形窗口…";
_getch();
closegraph();
return 0;
}