vc实现bezier曲面,要求用不同颜色显 示曲面和曲面的控制网格,并且可以取消曲面控制网格的显示,允 许交互式地改变控制网格的定点位置,以观看曲面形状的改变;能 够通过对话框、菜单等方式设置曲面的配置参数(书写代码)
时间: 2024-02-03 11:12:09 浏览: 109
下面是一个基于MFC框架的示例代码,用于实现bezier曲面的交互式显示和修改:
```
//BezierSurface.h
#pragma once
#include <vector>
#include <afxwin.h>
#include <afxdlgs.h>
using namespace std;
class BezierSurface : public CView
{
protected:
DECLARE_DYNCREATE(BezierSurface)
int m_nRows; //行数
int m_nCols; //列数
int m_nSelRow; //选中的行
int m_nSelCol; //选中的列
int m_nCtlPtSize; //控制点大小
bool m_bDrawGrid; //是否绘制控制网格
bool m_bDragging; //是否正在拖动控制点
bool m_bDraggingCtrlPt; //是否正在拖动控制点
CPoint m_ptDragStart; //拖动起始点
CPoint m_ptDragLast; //拖动过程中上一次的点
vector<vector<CPoint>> m_ctrlPts; //控制点集合
vector<vector<CPoint>> m_bezierPts;//bezier曲线集合
public:
BezierSurface();
virtual ~BezierSurface();
void Init(int nRows, int nCols);
void SetCtlPtSize(int nSize) { m_nCtlPtSize = nSize; }
void SetDrawGrid(bool bDraw) { m_bDrawGrid = bDraw; }
bool IsDrawGrid() const { return m_bDrawGrid; }
// Overrides
public:
virtual void OnDraw(CDC* pDC); //绘制函数
virtual void OnInitialUpdate(); //初始化函数
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
virtual void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView);
virtual void OnLButtonDown(UINT nFlags, CPoint point);
virtual void OnLButtonUp(UINT nFlags, CPoint point);
virtual void OnMouseMove(UINT nFlags, CPoint point);
virtual BOOL OnEraseBkgnd(CDC* pDC);
DECLARE_MESSAGE_MAP()
};
//BezierSurface.cpp
#include "stdafx.h"
#include "BezierSurface.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(BezierSurface, CView)
BezierSurface::BezierSurface()
{
m_nRows = 0;
m_nCols = 0;
m_nSelRow = -1;
m_nSelCol = -1;
m_nCtlPtSize = 5;
m_bDrawGrid = true;
m_bDragging = false;
m_bDraggingCtrlPt = false;
}
BezierSurface::~BezierSurface()
{
}
void BezierSurface::Init(int nRows, int nCols)
{
m_nRows = nRows;
m_nCols = nCols;
m_ctrlPts.resize(nRows);
m_bezierPts.resize(nRows);
for (int i = 0; i < nRows; i++) {
m_ctrlPts[i].resize(nCols);
m_bezierPts[i].resize(nCols);
for (int j = 0; j < nCols; j++) {
m_ctrlPts[i][j] = CPoint(i * 50, j * 50); //初始化控制点
}
}
}
void BezierSurface::OnDraw(CDC* pDC)
{
//绘制bezier曲面
for (int i = 0; i < m_nRows - 3; i++) {
for (int j = 0; j < m_nCols - 3; j++) {
//计算bezier曲线
for (double t = 0.0; t <= 1.0; t += 0.01) {
double u = 1.0 - t;
double x = 0.0, y = 0.0, z = 0.0;
for (int k = 0; k <= 3; k++) {
for (int l = 0; l <= 3; l++) {
double b = 1.0;
for (int m = 0; m < k; m++) {
b *= (u + m / 3.0);
}
for (int n = 0; n < 3 - k; n++) {
b *= (t + n / 3.0);
}
x += b * m_ctrlPts[i + k][j + l].x;
y += b * m_ctrlPts[i + k][j + l].y;
}
}
pDC->SetPixel(int(x), int(y), RGB(255, 0, 0));
}
}
}
if (m_bDrawGrid) {
//绘制控制网格
CPen pen(PS_SOLID, 1, RGB(192, 192, 192));
CPen* pOldPen = pDC->SelectObject(&pen);
for (int i = 0; i < m_nRows; i++) {
for (int j = 0; j < m_nCols; j++) {
if (i < m_nRows - 1) {
pDC->MoveTo(m_ctrlPts[i][j]);
pDC->LineTo(m_ctrlPts[i + 1][j]);
}
if (j < m_nCols - 1) {
pDC->MoveTo(m_ctrlPts[i][j]);
pDC->LineTo(m_ctrlPts[i][j + 1]);
}
}
}
pDC->SelectObject(pOldPen);
}
//绘制控制点
for (int i = 0; i < m_nRows; i++) {
for (int j = 0; j < m_nCols; j++) {
if (i == m_nSelRow && j == m_nSelCol) {
pDC->SelectStockObject(BLACK_BRUSH);
pDC->SelectStockObject(BLACK_PEN);
}
else {
pDC->SelectStockObject(WHITE_BRUSH);
pDC->SelectStockObject(BLACK_PEN);
}
pDC->Ellipse(m_ctrlPts[i][j].x - m_nCtlPtSize, m_ctrlPts[i][j].y - m_nCtlPtSize,
m_ctrlPts[i][j].x + m_nCtlPtSize, m_ctrlPts[i][j].y + m_nCtlPtSize);
}
}
}
void BezierSurface::OnInitialUpdate()
{
CView::OnInitialUpdate();
SetScrollSizes(MM_TEXT, CSize(0, 0));
}
BOOL BezierSurface::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}
void BezierSurface::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
Invalidate();
}
void BezierSurface::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
if (bActivate) {
GetParentFrame()->SetWindowText(_T("Bezier Surface"));
}
}
void BezierSurface::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rc;
for (int i = 0; i < m_nRows; i++) {
for (int j = 0; j < m_nCols; j++) {
rc.SetRect(m_ctrlPts[i][j].x - m_nCtlPtSize, m_ctrlPts[i][j].y - m_nCtlPtSize,
m_ctrlPts[i][j].x + m_nCtlPtSize, m_ctrlPts[i][j].y + m_nCtlPtSize);
if (rc.PtInRect(point)) {
m_bDragging = true;
m_bDraggingCtrlPt = true;
m_nSelRow = i;
m_nSelCol = j;
m_ptDragStart = point;
m_ptDragLast = point;
SetCapture();
return;
}
}
}
}
void BezierSurface::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bDragging) {
ReleaseCapture();
m_bDragging = false;
if (m_bDraggingCtrlPt) {
m_bDraggingCtrlPt = false;
}
else {
m_nSelRow = -1;
m_nSelCol = -1;
}
Invalidate();
}
}
void BezierSurface::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bDragging) {
if (m_bDraggingCtrlPt) {
m_ctrlPts[m_nSelRow][m_nSelCol] += point - m_ptDragLast;
m_ptDragLast = point;
}
else {
int dx = point.x - m_ptDragStart.x;
int dy = point.y - m_ptDragStart.y;
for (int i = 0; i < m_nRows; i++) {
for (int j = 0; j < m_nCols; j++) {
m_ctrlPts[i][j].x += dx;
m_ctrlPts[i][j].y += dy;
}
}
m_ptDragStart = point;
}
Invalidate();
}
}
BOOL BezierSurface::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
BEGIN_MESSAGE_MAP(BezierSurface, CView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
```
使用方法:
1. 在主窗口的OnInitDialog函数中添加以下代码,初始化BezierSurface视图:
```
m_bezierView = new BezierSurface();
m_bezierView->Create(NULL, NULL, WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, ID_VIEW_BEZIER, NULL);
m_bezierView->Init(5, 5); //设置行数和列数
```
2. 在主窗口创建菜单,并添加响应函数,以便用户可以选择是否显示控制网格:
```
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if (!bSysMenu) {
if (pPopupMenu->GetMenuItemID(0) == ID_VIEW_DRAWGRID) {
pPopupMenu->CheckMenuItem(ID_VIEW_DRAWGRID, m_bezierView->IsDrawGrid() ? MF_CHECKED : MF_UNCHECKED);
}
}
CMDIFrameWndEx::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
void CMainFrame::OnViewDrawgrid()
{
m_bezierView->SetDrawGrid(!m_bezierView->IsDrawGrid());
m_bezierView->Invalidate();
}
```
3. 在BezierSurface视图中添加对话框,以便用户可以设置曲面的配置参数:
```
void BezierSurface::OnConfig()
{
CDialog dlg(IDD_CONFIG_DIALOG, this);
dlg.DoModal();
}
```
4. 在对话框的OnInitDialog函数中添加控件,并添加响应函数,以便用户可以设置曲面的配置参数:
```
BOOL CConfigDialog::OnInitDialog()
{
CDialog::OnInitDialog();
m_nRowsCtrl.SetRange(2, 100);
m_nRowsCtrl.SetPos(m_pBezierView->GetRowCount());
m_nColsCtrl.SetRange(2, 100);
m_nColsCtrl.SetPos(m_pBezierView->GetColCount());
return TRUE;
}
void CConfigDialog::OnOK()
{
int nRows = m_nRowsCtrl.GetPos();
int nCols = m_nColsCtrl.GetPos();
m_pBezierView->Init(nRows, nCols);
CDialog::OnOK();
}
```
阅读全文