【计算机图形学】实验二:曲线拟合

简介: 【计算机图形学】实验二:曲线拟合

1. 实验内容

1. 绘制三次Bezier曲线

(1)给定四个已知点P1—P4,以此作为控制顶点绘制一段三次Bezier曲线。

(2)给定四个已知点P1—P4,以此作为曲线上的点绘制一段三次Bezier曲线。

2.绘制三次B样条曲线

给定六个已知点P1—P6,以此作为控制顶点绘制一条三次B样条曲线。

2. 实验环境

Visual Studio 2019

图形学实验程序框架

Windows11系统

3. 问题分析

3.1问题1(1)

对于问题1(1),三次Bezier曲线的矩阵表示形式如下:

image.png


image.png

3.2问题1(2)


image.png

image.png

image.png



解得:


image.png

image.png

3.3问题2

对于问题2,三次B样条曲线的矩阵表示形式如下:

image.png


一段三次B样条曲线需要4个控制点。但在已有三次B样条曲线的情况下,可以额外增加一个控制点,即可相应地增加一段B样条曲线,自然地能达到C 2 C_2C2连续。

4. 算法设计

4.1问题1(1)

正如3.1所分析,算法的流程如下:

image.png


3.循环第2步,直到t = 1 t=1t=1时结束。

算法的流程图如下:

4.2问题2

正如章节3.2分析,算法的流程如下:


image.png

3.循环第2步,直到t=1时结束。

4.根据(10)式反推控制点,并将4个控制点连结成线。

4.3问题3


image.png

5. 源代码

5.1 Bezier1

//以已知的四个点为控制点绘制Bezier曲线
//p:已知的四个控制点
void CDiamondView::DrawBezier1(POINT p[4])
{
  InvalidateRect(NULL);//强制清屏
  UpdateWindow();
  CDC* pDC = GetDC();
  CPen newPen, * oldPen;
  newPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
  oldPen = pDC->SelectObject(&newPen);
  pDC->Polyline(p, 4);
  pDC->SelectObject(oldPen);
  CPen newPen2;
  newPen2.CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
  oldPen = pDC->SelectObject(&newPen2);
  double ax = -p[0].x + 3 * p[1].x - 3 * p[2].x + p[3].x;
  double ay = -p[0].y + 3 * p[1].y - 3 * p[2].y + p[3].y;
  double bx = 3 * p[0].x - 6 * p[1].x + 3 * p[2].x;
  double by = 3 * p[0].y - 6 * p[1].y + 3 * p[2].y;
  double cx = -3 * p[0].x + 3 * p[1].x;
  double cy = -3 * p[0].y + 3 * p[1].y;
  double dx = p[0].x;
  double dy = p[0].y;
  pDC->MoveTo(p[0].x, p[0].y);
  for (double t = 0; t <= 1; t = t + 0.001) {
    int xt = ax * t * t * t + bx * t * t + cx * t + dx;
    int yt = ay * t * t * t + by * t * t + cy * t + dy;
    pDC->LineTo(xt, yt);
  //  Sleep(10);
  }
  pDC->SelectObject(oldPen);
}

5.2 Bezier2

//以已知的四个点为Bezier曲线上的点来绘制Bezier曲线
//p:已知的四个点
void CDiamondView::DrawBezier2(POINT p[4])
{
  //假设控制点1的t1=0.25
  //假设控制点2的t2=0.5
  InvalidateRect(NULL);//强制清屏
  UpdateWindow();
  CDC* pDC = GetDC();
  CPen newPen, * oldPen;
  newPen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
  oldPen = pDC->SelectObject(&newPen);
  pDC->Polyline(p, 4);
  pDC->SelectObject(oldPen);
  POINT controlpoint[4];
  controlpoint[0] = p[0];//控制点0即为P0
  controlpoint[3] = p[3];//控制点1即为P1
  controlpoint[1].x = 3.5549 * (p[1].x - 0.4219 * p[0].x - 0.0156 * p[3].x) - 1.3329 * (p[2].x - 0.125 * p[0].x - 0.125 * p[3].x);
  controlpoint[1].y = 3.5549 * (p[1].y - 0.4219 * p[0].y - 0.0156 * p[3].y) - 1.3329 * (p[2].y - 0.125 * p[0].y - 0.125 * p[3].y);//反推控制点1坐标
  controlpoint[2].x = -3.5549*(p[1].x - 0.4219 * p[0].x - 0.0156 * p[3].x) + 3.9995 * (p[2].x - 0.125 * p[0].x - 0.125 * p[3].x);
  controlpoint[2].y = -3.5549 * (p[1].y - 0.4219 * p[0].y - 0.0156 * p[3].y) + 3.9995 * (p[2].y - 0.125 * p[0].y - 0.125 * p[3].y);//反推控制点2坐标
  CPen newPen1;
  newPen1.CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
  oldPen = pDC->SelectObject(&newPen1);
  pDC->Polyline(controlpoint, 4);
  pDC->MoveTo(p[0].x, p[0].y);
  pDC->SelectObject(oldPen);
  CPen newPen2;
  newPen2.CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
  oldPen = pDC->SelectObject(&newPen2);
  //反推ax、bx、cx、dx、ay、by、cy、dy
  double ax = 8.0 / 3.0 * p[3].x - 16 * p[2].x + 64.0 / 3.0 * p[1].x - 8 * p[0].x;
  double ay = 8.0 / 3.0 * p[3].y - 16 * p[2].y + 64.0 / 3.0 * p[1].y - 8 * p[0].y;
  double bx = -2 * p[3].x + 20 * p[2].x - 32 * p[1].x + 14 * p[0].x;
  double by = -2 * p[3].y + 20 * p[2].y - 32 * p[1].y + 14 * p[0].y;
  double cx = -7 * p[0].x + 32.0 / 3.0 * p[1].x - 4 * p[2].x + 1.0 / 3.0 * p[3].x;
  double cy = -7 * p[0].y + 32.0 / 3.0 * p[1].y - 4 * p[2].y + 1.0 / 3.0 * p[3].y;
  double dx = p[0].x;
  double dy = p[0].y;
  for (double t = 0; t <= 1; t = t + 0.001) {
    int xt = ax * t * t * t + bx * t * t + cx * t + dx;
    int yt = ay * t * t * t + by * t * t + cy * t + dy;
    pDC->LineTo(xt, yt);
    //  Sleep(10);
  }
  pDC->SelectObject(oldPen);
}

5.3 B样条曲线

//以已知的六个点为控制点来绘制B样条曲线
//p:已知的六个控制点
void CDiamondView::DrawBCurve(POINT p[6])
{
  InvalidateRect(NULL);//强制清屏
  UpdateWindow();
  CDC* pDC = GetDC();
  CPen newPen, * oldPen;
  newPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
  oldPen = pDC->SelectObject(&newPen);
  pDC->Polyline(p, 6);
  pDC->SelectObject(oldPen);
  CPen newPen2;
  newPen2.CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
  oldPen = pDC->SelectObject(&newPen2);
  for (int i = 0; i < 3; i++) {
    double ax = -(p[i].x - 3 * p[i + 1].x + 3 * p[i + 2].x - p[i + 3].x) / 6;
    double ay = -(p[i].y - 3 * p[i + 1].y + 3 * p[i + 2].y - p[i + 3].y) / 6;
    double bx = (p[i].x - 2 * p[i + 1].x + p[i + 2].x) / 2;
    double by = (p[i].y - 2 * p[i + 1].y + p[i + 2].y) / 2;
    double cx = -(p[i].x - p[i + 2].x) / 2;
    double cy = -(p[i].y - p[i + 2].y) / 2;
    double dx = (p[i].x + 4 * p[i + 1].x + p[i + 2].x) / 6;
    double dy = (p[i].y + 4 * p[i + 1].y + p[i + 2].y) / 6;
  //  pDC->MoveTo(p[i].x, p[i].y);
    for (double t = 0; t <= 1; t = t + 0.001) {
      int xt = ax * t * t * t + bx * t * t + cx * t + dx;
      int yt = ay * t * t * t + by * t * t + cy * t + dy;
      pDC->MoveTo(xt, yt);
      pDC->LineTo(xt, yt);
      //  Sleep(10);
    }
  }
  pDC->SelectObject(oldPen);
}

6.程序运行结果

正确地根据4个控制点绘制出了一条Bezier曲线,且将4个控制点连接绘制出来。

正确地根据曲线上4个点绘制出了一条Bezier曲线能够穿过这4个点,且将这4个点连接绘制出来。并且能够根据曲线本身反推控制点,将这4个点用蓝色的线连接绘制出来。

正确地根据6个控制点绘制了B样条曲线。

7.总结


目录
相关文章
|
7月前
|
机器学习/深度学习 算法 测试技术
【MATLAB】交叉验证求光滑因子的广义神经网络时序预测算法
【MATLAB】交叉验证求光滑因子的广义神经网络时序预测算法
114 0
|
7月前
|
算法 图形学
【计算机图形学】实验一 DDA算法、Bresenham算法
【计算机图形学】实验一 DDA算法、Bresenham算法
293 3
|
传感器 算法 计算机视觉
非线性非高斯模型的改进粒子滤波算法(Matlab代码实现)
非线性非高斯模型的改进粒子滤波算法(Matlab代码实现)
179 0
|
7月前
|
机器学习/深度学习 算法
【MATLAB】小波神经网络回归预测算法
【MATLAB】小波神经网络回归预测算法
109 1
|
7月前
|
机器学习/深度学习 算法
【MATLAB】交叉验证求光滑因子的广义神经网络回归预测算法
【MATLAB】交叉验证求光滑因子的广义神经网络回归预测算法
84 0
|
机器学习/深度学习 传感器 算法
【免费】基于径向基神经网络的时间序列预测附matlab代码
【免费】基于径向基神经网络的时间序列预测附matlab代码
|
机器学习/深度学习 算法
萤火虫模糊回归算法(Matlab代码实现)
萤火虫模糊回归算法(Matlab代码实现)
129 0
|
算法
面向高维优化问题的混沌粒子群混合蝴蝶优化算法(Matlab代码实现)
面向高维优化问题的混沌粒子群混合蝴蝶优化算法(Matlab代码实现)
113 0
|
算法 计算机视觉
改进的粒子滤波算法及其应用研究(Matlab代码实现)
改进的粒子滤波算法及其应用研究(Matlab代码实现)
181 0
|
机器学习/深度学习 传感器 算法
【RBF回归预测】基于径向基神经网络时间序列预测附Matlab完整源码
【RBF回归预测】基于径向基神经网络时间序列预测附Matlab完整源码