Geometric Transformation of 2D Graphics (Computer Graphics)

Note: The experimental code can run normally under vs2022, and this experiment is adapted to the second edition of the new version of computer graphics (VC++ MFC)

1. Purpose of the experiment

1) Master the programming implementation of 3*3 matrix multiplication operation

2) Master the generation of three basic two-dimensional geometric transformation matrices of translation, scale and rotation

3) Master the generation of two-dimensional composite transformation matrix relative to any reference point

2. Experimental requirements


1) Design and realize the two-dimensional graphics transformation class, which has the functions of translation, scale, and rotation two-dimensional geometric transformation, as well as the two-dimensional compound transformation function relative to any reference point; The rhombus wireframe shown rotates at a constant speed around the uppermost point A, and is required to scale back and forth relative to point A.
3) Use the double-buffering mechanism to draw graphics to avoid motion flickering. All graphics are first drawn to the user-defined DC, and then copied to the screen DC after the drawing is completed.

3. Experimental steps

This time, it is actually an addition and modification to the code of the previous linear scan conversion, without the need for a new project.

Code:

1)Line.h

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

2)Line.cpp

#include"pch.h"
#include"Line.h"
#include"math.h"
#define Round(d) int(floor(d+0.5))

CP2::CP2()
{
	x = 0.0;
	y = 0.0;
	w = 1.0;
};

CP2::~CP2()
{}

CP2::CP2(double x, double y)
{
	this->x = x;
	this->y = y;
	this->w = 1;
};

CLine::CLine()
{}

CLine::~CLine()
{}

void CLine::SetLineColor(COLORREF color)
{
	clr = color;
}
void CLine::MoveTo(CP2 p0)
{
	P0 = p0;
}
void CLine::MoveTo(double x, double y)
{
	P0.x = x;
	P0.y = y;
}
void CLine::LineTo(double x, double y, CDC* pDC)
{
	CP2 p;
	p.x = x;
	p.y = y;


	LineTo(p, pDC);
}
void CLine::LineTo(CP2 p1, CDC* pDC)
{
	P1 = p1;
	CP2 p, t;
	if (fabs(P0.x - P1.x) < 1e-6)
	{
		if (P0.y > P1.y)
		{
			t = P0; P0 = P1; P1 = t;
		}
		for (p = P0; p.y < P1.y; p.y++)
		{
			pDC->SetPixelV(Round(p.x), Round(p.y), clr);
		}
	}
	else
	{
		double k, d;
		k = (P1.y - P0.y) / (P1.x - P0.x);
		if (k > 1.0)
		{
			if (P0.y > P1.y)
			{
				t = P0; P0 = P1; P1 = t;
			}
			d = 1 - 0.5 * k;
			for (p = P0; p.y < P1.y; p.y++)
			{
				pDC->SetPixelV(Round(p.x), Round(p.y), clr);
				if (d >= 0)
				{
					p.x++;
					d += 1 - k;
				}
				else
					d += 1;
			}
		}
		if (0.0 <= k && k <= 1.0)
		{
			if (P0.x > P1.x)
			{
				t = P0; P0 = P1; P1 = t;
			}
			d = 0.5 - k;
			for (p = P0; p.x < P1.x; p.x++)
			{
				pDC->SetPixelV(Round(p.x), Round(p.y), clr);
				if (d < 0)
				{
					p.y++;
					d += 1 - k;
				}
				else
					d -= k;
			}
		}


		if (k >= -1.0 && k < 0.0)
		{
			if (P0.x > P1.x)
			{
				t = P0; P0 = P1; P1 = t;
			}
			d = -0.5 - k;
			for (p = P0; p.x < P1.x; p.x++)
			{
				pDC->SetPixelV(Round(p.x), Round(p.y), clr);
				if (d > 0)
				{
					p.y--;
					d -= 1 + k;
				}
				else
					d -= k;
			}
		}
		if (k < -1.0)
		{
			if (P0.y > P1.y)
			{
				t = P0; P0 = P1; P1 = t;
			}
			d = -1 - 0.5 * k;
			for (p = P0; p.y > P1.y; p.y--)
			{
				pDC->SetPixelV(Round(p.x), Round(p.y), clr);
				if (d < 0)
				{
					p.x++;
					d -= 1 + k;
				}
				else
					d -= 1;
			}
		}
	}
	P0 = p1;
}

3) Create a new header file CTrans2D.h

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

4) Create a new source file CTrans2D.cpp

#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);
	//baotu
}
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;
}

5)TestView.cpp

Only the drawing function in TestView.cpp is modified, and other codes remain unchanged

Need to import header file

#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);
	//====================================================
	//CP2 B(a, 0);
	//CP2 C(0, -a);
	//CP2 D(-a, 0);
	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);
}

Experimental results:

e6a4f9515f2a49e08695c6a05482824b.png

 

 

Guess you like

Origin blog.csdn.net/m0_63975371/article/details/127237532