根据三次Bezier曲线的基函数,使用MFC编程绘制下图所示的三次Bezier曲线。要求可以使用鼠标左键拖动控制多边形的顶点,同时曲线能随之发生变化。
时间: 2023-06-18 13:07:57 浏览: 124
以下是使用MFC编程绘制三次Bezier曲线的示例代码:
首先,在MFC的框架下创建一个新的MFC应用程序,然后在View类中添加以下代码:
```
class CBezierCurveView : public CView
{
protected: // create from serialization only
CBezierCurveView() noexcept;
DECLARE_DYNCREATE(CBezierCurveView)
// Attributes
public:
CBezierCurveDoc* GetDocument() const;
// Operations
public:
void OnDrawBezier(CDC* pDC, CPoint* pPoints, int nCount);
// Overrides
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnInitialUpdate(); // called first time after construct
// Implementation
public:
virtual ~CBezierCurveView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
private:
BOOL m_bDragging;
CPoint m_DragPoint;
CPoint m_Points[4];
};
```
在View类的cpp文件中添加以下代码:
```
IMPLEMENT_DYNCREATE(CBezierCurveView, CView)
BEGIN_MESSAGE_MAP(CBezierCurveView, CView)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
// CBezierCurveView construction/destruction
CBezierCurveView::CBezierCurveView() noexcept
{
m_bDragging = FALSE;
}
CBezierCurveView::~CBezierCurveView()
{
}
BOOL CBezierCurveView::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}
void CBezierCurveView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// 初始化多边形的顶点
m_Points[0] = CPoint(100, 200);
m_Points[1] = CPoint(200, 100);
m_Points[2] = CPoint(400, 300);
m_Points[3] = CPoint(500, 200);
}
// CBezierCurveView drawing
void CBezierCurveView::OnDraw(CDC* pDC)
{
CBezierCurveDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
OnDrawBezier(pDC, m_Points, 4);
}
void CBezierCurveView::OnDrawBezier(CDC* pDC, CPoint* pPoints, int nCount)
{
// 绘制多边形的边
for (int i = 0; i < nCount - 1; i++)
{
pDC->MoveTo(pPoints[i]);
pDC->LineTo(pPoints[i + 1]);
}
// 计算Bezier曲线上的点
CPoint points[100];
for (int i = 0; i < 100; i++)
{
double t = double(i) / 99;
double a = (1 - t) * (1 - t) * (1 - t);
double b = 3 * t * (1 - t) * (1 - t);
double c = 3 * t * t * (1 - t);
double d = t * t * t;
double x = a * pPoints[0].x + b * pPoints[1].x + c * pPoints[2].x + d * pPoints[3].x;
double y = a * pPoints[0].y + b * pPoints[1].y + c * pPoints[2].y + d * pPoints[3].y;
points[i].x = int(x + 0.5);
points[i].y = int(y + 0.5);
}
// 绘制Bezier曲线
for (int i = 0; i < 99; i++)
{
pDC->MoveTo(points[i]);
pDC->LineTo(points[i + 1]);
}
}
// CBezierCurveView diagnostics
#ifdef _DEBUG
void CBezierCurveView::AssertValid() const
{
CView::AssertValid();
}
void CBezierCurveView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CBezierCurveDoc* CBezierCurveView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBezierCurveDoc)));
return (CBezierCurveDoc*)m_pDocument;
}
#endif //_DEBUG
// CBezierCurveView 消息处理程序
void CBezierCurveView::OnLButtonDown(UINT nFlags, CPoint point)
{
for (int i = 0; i < 4; i++)
{
if (abs(point.x - m_Points[i].x) < 5 && abs(point.y - m_Points[i].y) < 5)
{
m_bDragging = TRUE;
m_DragPoint = point;
break;
}
}
CView::OnLButtonDown(nFlags, point);
}
void CBezierCurveView::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bDragging)
{
for (int i = 0; i < 4; i++)
{
if (m_DragPoint == m_Points[i])
{
m_Points[i] = point;
break;
}
}
Invalidate();
}
CView::OnMouseMove(nFlags, point);
}
void CBezierCurveView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bDragging = FALSE;
CView::OnLButtonUp(nFlags, point);
}
```
在Document类中添加以下代码:
```
class CBezierCurveDoc : public CDocument
{
protected: // create from serialization only
CBezierCurveDoc() noexcept;
DECLARE_DYNCREATE(CBezierCurveDoc)
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
#ifdef SHARED_HANDLERS
virtual void InitializeSearchContent();
virtual void OnDrawThumbnail(CDC& dc, LPRECT lprcBounds);
#endif // SHARED_HANDLERS
// Implementation
public:
virtual ~CBezierCurveDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
#ifdef SHARED_HANDLERS
// Helper function that sets search content for a Search Handler
void SetSearchContent(const CString& value);
#endif // SHARED_HANDLERS
};
```
在Document类的cpp文件中添加以下代码:
```
IMPLEMENT_DYNCREATE(CBezierCurveDoc, CDocument)
BEGIN_MESSAGE_MAP(CBezierCurveDoc, CDocument)
END_MESSAGE_MAP()
CBezierCurveDoc::CBezierCurveDoc() noexcept
{
}
CBezierCurveDoc::~CBezierCurveDoc()
{
}
BOOL CBezierCurveDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
return TRUE;
}
void CBezierCurveDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
}
else
{
}
}
#ifdef SHARED_HANDLERS
// Support for thumbnails
void CBezierCurveDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
{
// Modify this code to draw the document's data
dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));
CString strText = _T("TODO: implement thumbnail drawing here");
LOGFONT lf;
CFont* pDefaultGUIFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
pDefaultGUIFont->GetLogFont(&lf);
lf.lfHeight = 36;
CFont fontDraw;
fontDraw.CreateFontIndirect(&lf);
CFont* pOldFont = dc.SelectObject(&fontDraw);
dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
dc.SelectObject(pOldFont);
}
// Support for Search Handlers
void CBezierCurveDoc::InitializeSearchContent()
{
CString strSearchContent;
// Set search contents from document's data.
// The content parts should be separated by ";"
// TODO: add additional content here
strSearchContent = _T("TODO: implement search content");
SetSearchContent(strSearchContent);
}
void CBezierCurveDoc::SetSearchContent(const CString& value)
{
if (value.IsEmpty())
{
RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);
}
else
{
CMFCFilterChunkValueImpl *pChunk = NULL;
ATLTRY(pChunk = new CMFCFilterChunkValueImpl);
if (pChunk != NULL)
{
pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);
SetChunkValue(pChunk);
}
}
}
#endif // SHARED_HANDLERS
#ifdef _DEBUG
void CBezierCurveDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CBezierCurveDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
```
最后,在MainFrame类中添加以下代码:
```
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame() noexcept;
DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
CMainFrame::CMainFrame() noexcept
{
}
CMainFrame::~CMainFrame()
{
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
CRect rect;
GetClientRect(rect);
pContext->m_pNewViewClass = RUNTIME_CLASS(CBezierCurveView);
pContext->m_pCurrentDoc = new CBezierCurveDoc;
pContext->m_pNewDocTemplate = NULL;
return CreateView(pContext, AFX_IDW_PANE_FIRST);
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
return 0;
}
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
```
现在可以运行程序并使用鼠标左键拖动多边形的顶点,观察Bezier曲线的变化。
阅读全文