计算机图形学——二维图形几何转换


一、实验目的

  1. 掌握3*3矩阵乘法运算的编程实现;
  2. 掌握平移、比例、旋转三种基本二维几何变换矩阵的生成;
  3. 掌握相对于任意参考点的二维复合变换矩阵生成。

二、实验要求

  1. 设计实现二维图形变换类,具有平移、比例、旋转二位几何变换的功能,以及相对于任意参考点的二维复合变换功能;
  2. 将直线类所绘制的菱形线框,绕最上端A点匀速旋转,并要求相对于A点来回缩放;
  3. 使用双缓冲机制进行图形绘制,避免运动闪烁,所有图形先绘制到用户自定的DC,绘制完成后再统一拷贝到屏幕DC。

三、实验步骤

1.打开直线扫面转换MFC项目工程,及其中的直线类CLine。

2.二维点类CP2添加齐次坐标

代码如下:

#pragma once
class CP2
{
public:
	CP2();
	virtual~CP2();
	CP2(double, double);
public:
	double x;
	double y;
	double w;
};


class CLine
{
public:
	CLine();
	virtual~CLine();
	void SetLineColor(COLORREF);
	void MoveTo(CP2);
	void MoveTo(double, double);
	void LineTo(CP2, CDC*);
	void LineTo(double, double, CDC*);
public:
	CP2 P0;
	CP2 P1;
	COLORREF clr;
};

3.设计实现二维图像几何变换类

1、新建二维图形几何变换类CTrans2D头文件

代码如下:

#pragma once
#include "Line.h"

class CTrans2D // 二维几何转换
{
public:
	CTrans2D();
	virtual~CTrans2D();
	void SetPoints(CP2*, int);
	void Identity();
	void Translate(double, double); // 平移变换矩阵
	void Rotate(double); // 旋转变换矩阵
	void Scale(double, double); // 比例变换矩阵
	void RotatePoint(double, CP2); // 相对于任意点的旋转变换矩阵
	void ScalePoint(double, double, CP2); // 相对于任意点的比例变换矩阵
protected:
	void MultiMatrix(); // 矩阵相乘
public:
	double m_aT[3][3];
	CP2* m_pPoints;
	int m_iNum;
};
2、新建二维图形几何变换类CTrans2D源文件
#include "pch.h"
#include "CTrans2D.h"
#include "math.h"
#define PI 3.14159
CTrans2D::CTrans2D()
{}
CTrans2D::~CTrans2D()
{}

void CTrans2D::SetPoints(CP2* p, int n)
{
	m_pPoints = p;
	m_iNum = n;
}

void CTrans2D::Identity() // 单位矩阵
{
	m_aT[0][0] = 1.0; m_aT[0][1] = 0.0; m_aT[0][2] = 0.0;
	m_aT[1][0] = 0.0; m_aT[1][1] = 1.0; m_aT[1][2] = 0.0;
	m_aT[2][0] = 0.0; m_aT[2][1] = 0.0; m_aT[2][2] = 1.0;
}
void CTrans2D::Translate(double tx, double ty) // 平移变换矩阵
{
	Identity();
	m_aT[2][0] = tx;
	m_aT[2][1] = ty;
	MultiMatrix();
}
void CTrans2D::Rotate(double beta) // 旋转变换矩阵
{
	Identity();
	double rad = beta * PI / 180;
	m_aT[0][0] = cos(rad);
	m_aT[0][1] = sin(rad);
	m_aT[1][0] = -sin(rad);
	m_aT[1][1] = cos(rad);
	MultiMatrix();
}

void CTrans2D::Scale(double sx, double sy) // 比例变换矩阵
{
	Identity();
	m_aT[0][0] = sx;
	m_aT[1][1] = sy;
	MultiMatrix();
}


void CTrans2D::RotatePoint(double beta, CP2 p) // 相对于任意点的旋转变换矩阵
{
	Translate(-p.x, -p.y);
	Rotate(beta);
	Translate(p.x, p.y);
}


void CTrans2D::ScalePoint(double sx, double sy, CP2 p) // 相对于任意点的整体比例变换矩阵
{
	Translate(-p.x, -p.y);
	Scale(sx, sy);
	Translate(p.x, p.y);
}


void CTrans2D::MultiMatrix() // 矩阵相乗
{
	CP2* PNew = new CP2[m_iNum];
	for (int i = 0; i < m_iNum; i++)
	{
		PNew[i] = m_pPoints[i];
	}
	for (int j = 0; j < m_iNum; j++)
	{
		m_pPoints[j].x = PNew[j].x * m_aT[0][0] + PNew[j].y * m_aT[1][0] + PNew[j].w * m_aT[2][0];
		m_pPoints[j].y = PNew[j].x * m_aT[0][1] + PNew[j].y * m_aT[1][1] + PNew[j].w * m_aT[2][1];
		m_pPoints[j].w = PNew[j].x * m_aT[0][2] + PNew[j].y * m_aT[1][2] + PNew[j].w * m_aT[2][2];
	}
	delete[]PNew;
}
3、调用二维图形几何变换类转动、缩放菱形线框图
#include "CTrans2D.h"
void CTestView::OnDraw(CDC* pDC)
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	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; // 内存DC
	CBitmap NewBitmap, * pOldBitmap; // 内存中承载的临时位图
	MemDC.CreateCompatibleDC(pDC); // 建立与屏幕pDC兼容的MemDC
	NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); // 创建兼容位图
	pOldBitmap = MemDC.SelectObject(&NewBitmap); // 将兼容位图选入MemDC
	MemDC.FillSolidRect(rect, pDC->GetBkColor()); // 按原来背景填充客户区,否则未黑色
	MemDC.SetMapMode(MM_ANISOTROPIC); // MemDC自定义坐标系与pDC相同
	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(0, 0, 0));
	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);

	int a = 200;
	CP2 points[4];
	points[0].x = 0, points[0].y = a;
	points[1].x = a, points[1].y = 0;
	points[2].x = 0, points[2].y = -a;
	points[3].x = -a, points[3].y = 0;
	
	CP2 A(0, a);
	CTrans2D tans;
	tans.SetPoints(points, 4);
	static float s = 1.0;
	static float step = 0.01;
	if (s >= 2.0 || s <= 0.5)
		step = -step;
	s += step;
	tans.ScalePoint(s, s, A);
	static float theta = 0.0;
	theta += 1.0;
	if (theta >= 360.0)
		theta = 0.0;
	tans.RotatePoint(theta, A);


	line->SetLineColor(RGB(255, 0, 0));
	line->MoveTo(points[0]);
	line->LineTo(points[1], &MemDC);

	line->SetLineColor(RGB(0, 255, 0));
	line->LineTo(points[2], &MemDC);

	line->SetLineColor(RGB(0, 0, 255));
	line->LineTo(points[3], &MemDC);

	line->SetLineColor(RGB(255, 255, 0));
	line->LineTo(points[0], &MemDC);

	delete line;

	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);
}

实验结果

请添加图片描述


  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值