使用VC++6.0用鼠标左键确定四个控制点,画出控制线,然后鼠标右键分别绘制三次Bezier曲线和三次B样条曲线。
时间: 2023-06-19 11:07:22 浏览: 153
用vc++实现Bezier曲线
5星 · 资源好评率100%
以下是使用MFC和VC++6.0实现的代码:
```
#include "stdafx.h"
#include "BezierBsplines.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define MAX_CONTROL_POINTS 4
#define MAX_CURVE_POINTS 200
#define BEZIER_CURVE 0
#define BSPLINE_CURVE 1
/////////////////////////////////////////////////////////////////////////////
// CBezierBsplinesApp
BEGIN_MESSAGE_MAP(CBezierBsplinesApp, CWinApp)
//{{AFX_MSG_MAP(CBezierBsplinesApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBezierBsplinesApp construction
CBezierBsplinesApp::CBezierBsplinesApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CBezierBsplinesApp object
CBezierBsplinesApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CBezierBsplinesApp initialization
BOOL CBezierBsplinesApp::InitInstance()
{
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CBezierBsplinesDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
void CBezierBsplinesApp::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
static int curPoint = 0;
if (curPoint < MAX_CONTROL_POINTS)
{
m_controlPoints[curPoint++] = point;
DrawControlPoints();
}
CWinApp::OnLButtonDown(nFlags, point);
}
void CBezierBsplinesApp::DrawControlPoints()
{
// Draw all control points
CClientDC dc(m_pMainWnd);
CBrush brush;
brush.CreateSolidBrush(RGB(0, 0, 255));
CBrush* pOldBrush = dc.SelectObject(&brush);
for (int i = 0; i < MAX_CONTROL_POINTS; i++)
{
dc.Ellipse(m_controlPoints[i].x - 2, m_controlPoints[i].y - 2, m_controlPoints[i].x + 2, m_controlPoints[i].y + 2);
}
dc.SelectObject(pOldBrush);
// Draw control lines
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
CPen* pOldPen = dc.SelectObject(&pen);
dc.MoveTo(m_controlPoints[0]);
for (int i = 1; i < MAX_CONTROL_POINTS; i++)
{
dc.LineTo(m_controlPoints[i]);
}
dc.SelectObject(pOldPen);
}
void CBezierBsplinesApp::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
static int curveType = BEZIER_CURVE;
if (curveType == BEZIER_CURVE)
{
DrawBezierCurve();
}
else if (curveType == BSPLINE_CURVE)
{
DrawBSplineCurve();
}
curveType = (curveType + 1) % 2;
CWinApp::OnRButtonDown(nFlags, point);
}
void CBezierBsplinesApp::DrawBezierCurve()
{
// Draw Bezier curve
CClientDC dc(m_pMainWnd);
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
CPen* pOldPen = dc.SelectObject(&pen);
for (int i = 0; i < MAX_CURVE_POINTS; i++)
{
double t = (double)i / (MAX_CURVE_POINTS - 1);
CPoint pt = CalculateBezierPoint(t);
if (i == 0)
{
dc.MoveTo(pt);
}
else
{
dc.LineTo(pt);
}
}
dc.SelectObject(pOldPen);
}
void CBezierBsplinesApp::DrawBSplineCurve()
{
// Draw B-spline curve
CClientDC dc(m_pMainWnd);
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
CPen* pOldPen = dc.SelectObject(&pen);
for (int i = 0; i < MAX_CURVE_POINTS; i++)
{
double t = (double)i / (MAX_CURVE_POINTS - 1);
CPoint pt = CalculateBSplinePoint(t);
if (i == 0)
{
dc.MoveTo(pt);
}
else
{
dc.LineTo(pt);
}
}
dc.SelectObject(pOldPen);
}
CPoint CBezierBsplinesApp::CalculateBezierPoint(double t)
{
// Calculate Bezier point
CPoint pt;
pt.x = (int)(pow(1 - t, 3) * m_controlPoints[0].x +
3 * t * pow(1 - t, 2) * m_controlPoints[1].x +
3 * pow(t, 2) * (1 - t) * m_controlPoints[2].x +
pow(t, 3) * m_controlPoints[3].x);
pt.y = (int)(pow(1 - t, 3) * m_controlPoints[0].y +
3 * t * pow(1 - t, 2) * m_controlPoints[1].y +
3 * pow(t, 2) * (1 - t) * m_controlPoints[2].y +
pow(t, 3) * m_controlPoints[3].y);
return pt;
}
CPoint CBezierBsplinesApp::CalculateBSplinePoint(double t)
{
// Calculate B-spline point
CPoint pt;
double b0 = pow(1 - t, 3) / 6;
double b1 = (3 * pow(t, 3) - 6 * pow(t, 2) + 4) / 6;
double b2 = (-3 * pow(t, 3) + 3 * pow(t, 2) + 3 * t + 1) / 6;
double b3 = pow(t, 3) / 6;
pt.x = (int)(b0 * m_controlPoints[0].x +
b1 * m_controlPoints[1].x +
b2 * m_controlPoints[2].x +
b3 * m_controlPoints[3].x);
pt.y = (int)(b0 * m_controlPoints[0].y +
b1 * m_controlPoints[1].y +
b2 * m_controlPoints[2].y +
b3 * m_controlPoints[3].y);
return pt;
}
```
这里的`CBezierBsplinesDlg`是使用MFC的对话框类,可以使用Visual Studio创建。
在对话框类的`OnInitDialog()`函数中,我们可以添加以下代码:
```
// Initialize control points
m_controlPoints[0] = CPoint(100, 100);
m_controlPoints[1] = CPoint(150, 200);
m_controlPoints[2] = CPoint(250, 200);
m_controlPoints[3] = CPoint(300, 100);
// Draw control points
DrawControlPoints();
```
这里我们初始化了四个控制点,并且调用`DrawControlPoints()`函数绘制控制点和控制线。
在`OnLButtonDown()`函数中,我们处理鼠标左键按下事件,如果当前控制点数量小于4,则将当前鼠标位置作为一个新的控制点,并调用`DrawControlPoints()`函数重新绘制控制点和控制线。
在`OnRButtonDown()`函数中,我们处理鼠标右键按下事件,根据当前曲线类型(Bezier曲线或B样条曲线),调用对应的函数`DrawBezierCurve()`或`DrawBSplineCurve()`绘制曲线,并将曲线类型切换为下一个类型。
在`DrawBezierCurve()`和`DrawBSplineCurve()`函数中,我们分别使用`CalculateBezierPoint()`和`CalculateBSplinePoint()`函数计算曲线上的点,并使用`CClientDC`和`CPen`绘制曲线。
在`CalculateBezierPoint()`函数中,我们使用Bezier曲线的公式计算曲线上的点。
在`CalculateBSplinePoint()`函数中,我们使用B样条曲线的公式计算曲线上的点。
最后,我们在`CBezierBsplinesApp`类中定义了`m_controlPoints`数组存储四个控制点,在`DrawControlPoints()`函数中绘制控制点和控制线,在`CalculateBezierPoint()`函数和`CalculateBSplinePoint()`函数中计算曲线上的点。
阅读全文