凸多边形隐线算法-计算机图形学

隐线算法

一、实验目的

(1)掌握凸多边形的隐线算法;

二、实验要求

(1)三维坐标系的原点位于屏幕中心,X轴水平向右,X轴垂直向上,Z轴垂直于坐标屏幕,指向屏幕外。

(2)使用实验五的绘制的动态正四面体线框图形为基础,通过隐线算法对正四面体的线框图进行消隐处理。

(3)使用点表和面表的双表结构,重新构造正四面体的数据

ps:本实验运行环境为Visual Studio2022

前面的实验可以搜直线扫描转换(中点Bresenham扫描转换算法),那个博主写的很全,代码也都在。

三、实验过程
  1. 打开实验四MFC工程文件(3D扫描转换转换)
  2. 在CP3Edge.h/cpp中添加表面类类

图3.2.1 在CP3Edge.h头文件中添加表面类

图3.2.2 在CP3Edge.cpp源文件中添加边表类

(3)建立正四面体的点表和边表

表3-1 正四面体的面表

 

图3.3.1 在_.view.h头文件中添加成员函数

图3.3.2 在_.view.h头文件中存储成员变量

图3.3.3 在_view.cpp实现并调用面表函数

(4)通过隐线算法绘制正四面体的消隐线框图

图3.4.1 建立修Vector.h头文件

图3.4.2 建立Vector.cpp源文件

隐线算法中用到了三维矢量的运算,这里通过建立三维矢量类CVector来实现。矢量类中包含存储三个分量的成员变量,以及实现基本矢量运算的成员函数,包点乘、叉乘和单位化等运算。

(5)正四面体的消隐线框图绘制

图3.5.1 修改_view.cpp中Ondraw函数

四、实验结果

消隐算法

五、完整代码

CP3Edge.h

#pragma once
class CP3
{
public:
	CP3();
	virtual ~CP3();
	CP3(double, double, double);
public:
	double x;
	double y;
	double z;
	double w;
};
//边表类
class CEdge
{
public:
	CEdge();
	virtual ~CEdge();
	void SetPointsIndex(int, int);
public:
	int Start;
	int End;
};


//平面类
class CFace 
{
public:
		CFace();
		virtual ~CFace();
		void SetPoints(int *points, int num);

	public:
		int Num;
		int *Points;
};

CP3Edge.cpp

#include"pch.h"
#include"CP3Edge.h"
CP3::CP3()
{
	x = 0.0;
	y = 0.0;
	z = 0.0;
	w = 1.0;
}
CP3::~CP3()
{}
CP3::CP3(double x, double y, double z) {
	this->x = x;
	this->y = y;
	this->z = z;
	this->w = 1.0;
}
//边表类
CEdge::CEdge() {
	Start = 0;
	End = 0;
}
CEdge::~CEdge()
{}
void CEdge::SetPointsIndex(int start, int end) {
	Start = start;
	End = end;
}

// 表面类
CFace::CFace(){
	Num = 0;
	Points = NULL;
}

CFace::~CFace()
{
	if (Points)
	{
		delete[] Points;
		Points=NULL;
	}
}


void CFace::SetPoints(int *points, int num)
{
	Num = num;
	if(Points)
	{
		delete[] Points;
		Points = NULL;
	}
	Points = new int[Num];
	for (int i = 0; i < Num; i++)
		Points[i] = points[i];
}





 Vector.h

#pragma once
#include "CP3Edge.h"

class CVector {
public:
    CVector();
    virtual ~CVector();
    CVector(CP3); // 假设CP3是一个已经定义的类或结构体
    CVector(CP3,CP3); // 构造函数,用于计算两个点之间的向量

    double Mold(); // 矢量的模
    CVector Unit(); // 单位矢量

    // 运算符重载
    friend CVector operator +(const CVector &, const CVector &);
    friend CVector operator -(const CVector &, const CVector &);
    friend CVector operator *(const CVector &, double);
    friend CVector operator /(const CVector &, double);
    friend CVector operator +=(const CVector &, const CVector &);
    friend CVector operator-=(const CVector &, const CVector &);
    friend CVector operator*=(const CVector &, const CVector &);
    friend CVector operator/=(const CVector &, double);

    friend double Dot(CVector &,CVector &); // 矢量点积
    friend CVector operator *(CVector &,CVector &); // 矢量叉积

public:
    double x, y, z;
};

Vector.cpp

#include "pch.h"
#include "Vector.h"
#include "math.h"

CVector::CVector()
{
	x = 0.0;
	y = 0.0;
	z = 0.0;
}


CVector::~CVector()
{}

CVector::CVector(CP3 p)
{
	x = p.x;
	y = p.y;
	z = p.z;
}

CVector::CVector(CP3 p1,CP3 p2)
{
	x = p2.x-p1.x;
	y = p2.y-p1.y;
	z = p2.z-p1.z;
}

CVector CVector::Unit()
{
	CVector vector;
	double product = sqrt(x * x + y * y + z * z);
	if (fabs(product) < 1e-5)
		product = 1.0;
	vector.x = x / product;
	vector.y = y / product;
	vector.z = z / product;
	return vector;
}

double CVector::Mold()
{
	double product = sqrt(x * x + y * y + z * z);
	return product;
}
//矢量的和
CVector operator +(CVector &v1, CVector &v2)
{
	CVector vector;
	vector.x = v1.x + v2.x;
	vector.y = v1.y + v2.y;
	vector.z = v1.z + v2.z;
	return vector;
}

 //矢量的差
CVector operator -(CVector &v1, CVector &v2)
{
	CVector vector;
	vector.x = v1.x - v2.x;
	vector.y = v1.y - v2.y;
	vector.z = v1.z - v2.z;
	return vector;
}


//矢量和常量的积
CVector operator *(CVector &v,double k)
{
	CVector vector;
	vector.x = v.x * k;
	vector.y = v.y * k;
	vector.z = v.z * k;
	return vector;
}

//矢量数除
CVector operator /(CVector& v, double k)
{
	if (fabs(k) < 1e-6)
		k = 1.0;
	CVector vector;
	vector.x = v.x / k;
	vector.y = v.y / k;
	vector.z = v.z / k;
	return vector;
}


//+=运算符重载
CVector operator +=(CVector& v1, CVector& v2)
{
	v1.x = v1.x + v2.x;
	v1.y = v1.y + v2.y;
	v1.z = v1.z + v2.z;
	return v1;
}


//-=运算符重载
CVector operator -=(CVector& v1, CVector& v2)
{
	v1.x = v1.x - v2.x;
	v1.y = v1.y - v2.y;
	v1.z = v1.z - v2.z;
	return v1;
}

//*=运算符重载
CVector operator *=(CVector& v1, CVector& v2)
{
	v1.x = v1.x * v2.x;
	v1.y = v1.y * v2.y;
	v1.z = v1.z * v2.z;
	return v1;
}

///=运算符重载
CVector operator /=(CVector& v1, double k)
{
	v1.x = v1.x / k;
	v1.y = v1.y / k;
	v1.z = v1.z / k;
	return v1;
}


//矢量的点积
double Dot(CVector& v1, CVector& v2)
{
	return(v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
}


//矢量的叉积
CVector operator*(CVector& v1, CVector& v2)
{
	CVector vector;
	vector.x = v1.y * v2.z - v1.z * v2.y;
	vector.y = v1.z * v2.x - v1.x * v2.z;
	vector.z = v1.x * v2.y - v1.y * v2.x;
	return vector;
}

MFCApplication5view.h

#include "CP3Edge.h"


// MFCApplication5View.h: CMFCApplication5View 类的接口
//

#pragma once


class CMFCApplication5View : public CView
{
protected: // 仅从序列化创建
	CMFCApplication5View() noexcept;
	DECLARE_DYNCREATE(CMFCApplication5View)

// 特性
public:
	CMFCApplication5Doc* GetDocument() const;

// 操作
public:
	void BuildPointEdge();
	void BuildPointFace();
// 重写
public:
	virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
	

// 实现
public:
	virtual ~CMFCApplication5View();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	CP3 P[4];
	CEdge E[6];
	CFace F[4];
// 生成的消息映射函数
protected:
	afx_msg void OnFilePrintPreview();
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // MFCApplication5View.cpp 中的调试版本
inline CMFCApplication5Doc* CMFCApplication5View::GetDocument() const
   { return reinterpret_cast<CMFCApplication5Doc*>(m_pDocument); }
#endif

MFCApplication5view.cpp


// MFCApplication5View.cpp: CMFCApplication5View 类的实现
//

#include "pch.h"
#include "framework.h"


#include "Line.h"
#include "CTrans3D.h"
#include "Vector.h"




// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFCApplication5.h"
#endif

#include "MFCApplication5Doc.h"
#include "MFCApplication5View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCApplication5View

IMPLEMENT_DYNCREATE(CMFCApplication5View, CView)

BEGIN_MESSAGE_MAP(CMFCApplication5View, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCApplication5View::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
END_MESSAGE_MAP()



//CMFCApplication5View 构造/析构

CMFCApplication5View::CMFCApplication5View() noexcept
{
	// TODO: 在此处添加构造代码
	BuildPointFace();
}
void CMFCApplication5View::BuildPointFace()
{
	double d = 400;
	P[0].x = d / 2; P[0].y = d / 2; P[0].z = d / 2;
	P[1].x = d / 2; P[1].y = -d / 2; P[1].z = -d / 2;
	P[2].x = -d / 2; P[2].y = -d / 2; P[2].z = d / 2;
	P[3].x = -d / 2; P[3].y = d / 2; P[3].z = -d / 2;


	E[0].SetPointsIndex(0, 1);
	E[1].SetPointsIndex(0, 2);
	E[2].SetPointsIndex(0, 3);
	E[3].SetPointsIndex(1, 2);
	E[4].SetPointsIndex(1, 3);
	E[5].SetPointsIndex(2, 3);

	//面表
	int points[3];

	points[0] = 1, points[1] = 2, points[2] = 3;
	F[0].SetPoints(points, 3);
	points[0] = 0, points[1] = 3, points[2] = 2;
	F[1].SetPoints(points, 3);
	points[0] = 0, points[1] = 1, points[2] = 3;
	F[2].SetPoints(points, 3);
	points[0] = 0, points[1] = 2, points[2] = 1;
	F[3].SetPoints(points, 3);
}


CMFCApplication5View::~CMFCApplication5View()
{

}



/*


// CTTestView 构造/析构

CTTestView::CTTestView() noexcept
{
	// TODO: 在此处添加构造代码
	BuildPointEdge();
}
void CTTestView::BuildPointEdge()
{
	double d = 400;
	P[0].x = d / 2; P[0].y = d / 2; P[0].z = d / 2;
	P[1].x = d / 2; P[1].y = -d / 2; P[1].z = -d / 2;
	P[2].x = -d / 2; P[2].y = -d / 2; P[2].z = d / 2;
	P[3].x = -d / 2; P[3].y = d / 2; P[3].z = -d / 2;
	E[0].SetPointsIndex(0, 1);
	E[1].SetPointsIndex(0, 2);
	E[2].SetPointsIndex(0, 3);
	E[3].SetPointsIndex(1, 2);
	E[4].SetPointsIndex(1, 3);
	E[5].SetPointsIndex(2, 3);
}

CTTestView::~CTTestView()
{

}

*/









BOOL CMFCApplication5View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CMFCApplication5View 绘图

void CMFCApplication5View::OnDraw(CDC* pDC)
{
	CMFCApplication5Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码

	//1.设置坐标系
	CRect rect;
	GetClientRect(&rect);
	pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetWindowExt(rect.Width(), rect.Height());
	pDC->SetViewportExt(rect.Width(), -rect.Height());
	pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
	//	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);


	//双缓冲机制绘制
	CDC MemDC;
	CBitmap NewBitmap, * pOldBitmap;
	MemDC.CreateCompatibleDC(pDC);
	NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
	pOldBitmap = MemDC.SelectObject(&NewBitmap);
	MemDC.FillSolidRect(rect, pDC->GetBkColor());
	MemDC.SetMapMode(MM_ANISOTROPIC);
	MemDC.SetWindowExt(rect.Width(), rect.Height());
	MemDC.SetViewportExt(rect.Width(), -rect.Height());
	MemDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);

	CLine* line = new CLine;
	line->SetLineColor(RGB(188, 143, 143));
	line->MoveTo(CP2(-rect.Width() / 2, 0));
	line->LineTo(CP2(rect.Width() / 2, 0), &MemDC);
	line->MoveTo(CP2(0, -rect.Height() / 2));
	line->LineTo(CP2(0, rect.Height() / 2), &MemDC);

	//3.旋转、缩放、正交投影变换
	CTrans3D tans;
	tans.SetPoints(P, 4);
	static float s = 1.0;
	static float step = 0.01f;
	if (s >= 2.0 || s <= 0.5)
		step = -step;
	s += step;
	tans.Scale(s, s, s);

	static float theta = 0.0;
	theta += 1.0;
	if (theta >= 360.0)
		theta = 0.0;
	tans.RotateY(theta);
	tans.ProjXOY();

	//4.绘制四面体的消隐线框图
	CVector VS(CP3(0, 0, 1));
	for (int i = 0; i < 4; i++)
	{
		CVector V12(tans.m_p3Points[F[i].Points[0]], tans.m_p3Points[F[i].Points[1]]);
		CVector V23(tans.m_p3Points[F[i].Points[0]], tans.m_p3Points[F[i].Points[2]]);
		CVector Normal = V12 * V23;
		
		if (Dot(VS, Normal.Unit()) >= 0)
		{
			line->SetLineColor(RGB(0, 255, 0));
			line->MoveTo(tans.m_p2Screen[F[i].Points[0]]);
			line->LineTo(tans.m_p2Screen[F[i].Points[1]],&MemDC);
			line->LineTo(tans.m_p2Screen[F[i].Points[2]], &MemDC);
			line->LineTo(tans.m_p2Screen[F[i].Points[0]], &MemDC);
			
			
		}
	}
	delete line;

	//5.将内存位图拷贝到屏幕
	pDC->BitBlt(-rect.Width() / 2, -rect.Height() / 2, rect.Width(), rect.Height(), &MemDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);
	MemDC.SelectObject(pOldBitmap);
	NewBitmap.DeleteObject();
	Invalidate(FALSE);

}


// CMFCApplication5View 打印


void CMFCApplication5View::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CMFCApplication5View::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CMFCApplication5View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CMFCApplication5View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}

void CMFCApplication5View::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CMFCApplication5View::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CMFCApplication5View 诊断

#ifdef _DEBUG
void CMFCApplication5View::AssertValid() const
{
	CView::AssertValid();
}

void CMFCApplication5View::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMFCApplication5Doc* CMFCApplication5View::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplication5Doc)));
	return (CMFCApplication5Doc*)m_pDocument;
}
#endif //_DEBUG


// CMFCApplication5View 消息处理程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值