所需类
P2类
class CP2
{
public:
CP2(void);
virtual ~CP2(void);
CP2(double x, double y);
friend CP2 operator + (const CP2& p0, const CP2& p1);
friend CP2 operator - (const CP2& p0, const CP2& p1);
friend CP2 operator * (const CP2& p, double scalar);
friend CP2 operator * (double scalar, const CP2& p);
friend CP2 operator / (const CP2& p, double scalar);
friend CP2 operator += (CP2& p0, CP2& p1);
friend CP2 operator -= (CP2& p0, CP2& p1);
friend CP2 operator *= (CP2& p0, double scalar);
friend CP2 operator /= (CP2& p0, double scalar);
public:
double x;
double y;
double w;
};
此处重载了运算符,方便后面定义矩阵运算
#include "pch.h"
#include "P2.h"
CP2::CP2(void)
{
x = 0.0;
y = 0.0;
w = 1.0;
}
CP2::~CP2(void)
{
}
CP2::CP2(double x, double y)
{
this->x = x;
this->y = y;
this->w = 1.0;
}
CP2 operator+(const CP2& p0, const CP2& p1)
{
CP2 temp;
temp.x = p0.x + p1.x;
temp.y = p0.y + p1.y;
temp.w = p0.w + p1.w;
return temp;
}
CP2 operator-(const CP2& p0, const CP2& p1)
{
CP2 temp;
temp.x = p0.x - p1.x;
temp.y = p0.y - p1.y;
temp.w = p0.w - p1.w;
return temp;
}
CP2 operator*(const CP2& p, double scalar)
{
CP2 temp;
temp.x = p.x * scalar;
temp.y = p.y * scalar;
temp.w = p.w * scalar;
return temp;
}
CP2 operator*(double scalar, const CP2& p)
{
CP2 temp;
temp.x = scalar * p.x;
temp.y = scalar * p.y;
temp.w = scalar * p.w;
return temp;
}
CP2 operator/(const CP2& p, double scalar)
{
CP2 temp;
temp.x = p.x / scalar;
temp.y = p.y / scalar;
temp.w = p.w / scalar;
return temp;
}
CP2 operator+=(CP2& p0, CP2& p1)
{
CP2 temp;
temp.x = p0.x + p1.x;
temp.y = p0.y + p1.y;
temp.w = p0.w + p1.w;
return temp;
}
CP2 operator-=(CP2& p0, CP2& p1)
{
CP2 temp;
temp.x = p0.x - p1.x;
temp.y = p0.y - p1.y;
temp.w = p0.w - p1.w;
return temp;
return CP2();
}
CP2 operator*=(CP2& p0, double scalar)
{
CP2 temp;
temp.x = p0.x * scalar;
temp.y = p0.y * scalar;
temp.w = p0.w * scalar;
return temp;
}
CP2 operator/=(CP2& p0, double scalar)
{
CP2 temp;
temp.x = p0.x / scalar;
temp.y = p0.y / scalar;
temp.w = p0.w / scalar;
return temp;
}
P3类继承P2
#pragma once
#include "P2.h"
class CP3:public CP2
{
public:
CP3(void);
virtual~CP3(void);
CP3(double x, double y, double z);
public:
double z;
};
#include "pch.h"
#include "P3.h"
CP3::CP3(void)
{
x = 0; y = 0; z = 0; w = 1;
}
CP3::~CP3(void)
{
}
CP3::CP3(double x, double y, double z)
{
this->z = z;
}
定义面类Facet
#pragma once
class CFacet
{
public:
CFacet(void);
virtual ~CFacet(void);
void SetPtNumber(int Number);
public:
int Number;
int Index[4];//这里一个面有4个点
};
#include "pch.h"
#include "Facet.h"
CFacet::CFacet(void)
{
Number = 0;
for (int i = 0; i < 4; i++) {
Index[i] = 0;
}
}
CFacet::~CFacet(void)
{
}
void CFacet::SetPtNumber(int Number)
{
this->Number = Number;
}
定义三维变换类Transform3
#pragma once
#include"P3.h"
#define PI 3.14159265
#include<math.h>
class CTransform3
{
public:
CTransform3(void);
virtual ~CTransform3(void);
void SetMatrix(CP3* P, int ptNumber);//设置二维顶点数组
void Identity(void);//单位矩阵
void Translate(double tx, double ty, double tz);//平移
void Scale(double sx, double sy, double sz);//放缩
void Scale(double sx, double sy, double sz, CP3 p);//相对于任意点的比例变换
void Scale(double s);//整体缩放
void Scale(double s,CP3 p);//整体缩放
void RotateX(double beta);//绕X轴旋转
void RotateY(double beta);//绕Y轴旋转
void RotateZ(double beta);//绕Z轴旋转
void RotateX(double beta, CP3 p);//相对于任意点旋转
void RotateY(double beta, CP3 p);//相对于任意点旋转
void RotateZ(double beta, CP3 p);//相对于任意点旋转
void ReflectX(void);
void ReflectY(void);
void ReflectZ(void);
void ReflectXOY(void);
void ReflectYOZ(void);
void ReflectZOX(void);
void ShearX(double b, double c);//错切
void ShearY(double d, double f);//错切
void ShearZ(double g, double h);//错切
void MultiplyMatrix(void);//矩阵乘法
private:
double M[4][4];
CP3* P;
int ptNumber;
};
#include "pch.h"
#include "Transform3.h"
CTransform3::CTransform3(void)
{
P = nullptr;
ptNumber = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
M[i][j] = 0.0;
}
}
}
CTransform3::~CTransform3(void)
{
}
void CTransform3::SetMatrix(CP3* P, int ptNumber)
{
this->P = P;
this->ptNumber = ptNumber;
}
void CTransform3::Identity(void)
{
M[0][0] = 1.0; M[0][1] = 0.0; M[0][2] = 0.0, M[0][3] = 0.0;
M[1][0] = 0.0; M[1][1] = 1.0; M[1][2] = 0.0, M[1][3] = 0.0;
M[2][0] = 0.0; M[2][1] = 0.0; M[2][2] = 1.0, M[2][3] = 0.0;
M[3][0] = 0.0; M[3][1] = 0.0; M[3][2] = 0.0, M[3][3] = 1.0;
}
void CTransform3::Translate(double tx, double ty, double tz)
{
Identity();
M[0][3] = tx;
M[1][3] = ty;
M[2][3] = tz;
MultiplyMatrix();
}
void CTransform3::Scale(double sx, double sy, double sz)
{
Identity();
M[0][0] = sx;
M[1][1] = sy;
M[2][2] = sz;
MultiplyMatrix();
}
void CTransform3::Scale(double sx, double sy, double sz, CP3 p)
{
Translate(-p.x, -p.y, -p.z);
Scale(sx, sy, sz);
Translate(p.x, p.y, p.z);
}
void CTransform3::Scale(double s)
{
Identity();
M[0][0] = s;
M[1][1] = s;
M[2][2] = s;
MultiplyMatrix();
}
void CTransform3::Scale(double s, CP3 p)
{
Translate(-p.x, -p.y, -p.z);
Scale(s);
Translate(p.x, p.y, p.z);
}
void CTransform3::RotateX(double beta)
{
Identity();
beta = beta * PI / 180;
M[1][1] = cos(beta);
M[1][2] = -sin(beta);
M[2][1] = sin(beta);
M[2][2] = cos(beta);
MultiplyMatrix();
}
void CTransform3::RotateY(double beta)
{
Identity();
beta = beta * PI / 180;
M[0][0] = cos(beta);
M[0][2] = sin(beta);
M[2][0] = -sin(beta);
M[2][2] = cos(beta);
MultiplyMatrix();
}
void CTransform3::RotateZ(double beta)
{
Identity();
beta = beta * PI / 180;
M[0][0] = cos(beta);
M[0][1] = -sin(beta);
M[1][0] = sin(beta);
M[1][1] = cos(beta);
MultiplyMatrix();
}
void CTransform3::RotateX(double beta, CP3 p)
{
Translate(-p.x, -p.y, p.z);
RotateX(beta);
Translate(p.x, p.y, p.z);
}
void CTransform3::RotateY(double beta, CP3 p)
{
Translate(-p.x, -p.y, p.z);
RotateY(beta);
Translate(p.x, p.y, p.z);
}
void CTransform3::RotateZ(double beta, CP3 p)
{
Translate(-p.x, -p.y, p.z);
RotateZ(beta);
Translate(p.x, p.y, p.z);
}
void CTransform3::ReflectX(void)
{
Identity();
M[1][1] = -1;
M[2][2] = -1;
MultiplyMatrix();
}
void CTransform3::ReflectY(void)
{
Identity();
M[0][0] = -1;
M[2][2] = -1;
MultiplyMatrix();
}
void CTransform3::ReflectZ(void)
{
Identity();
M[0][0] = -1;
M[1][1] = -1;
MultiplyMatrix();
}
void CTransform3::ReflectXOY(void)
{
Identity();
M[2][2] = -1;
MultiplyMatrix();
}
void CTransform3::ReflectYOZ(void)
{
Identity();
M[0][0] = -1;
MultiplyMatrix();
}
void CTransform3::ReflectZOX(void)
{
Identity();
M[1][1] = -1;
MultiplyMatrix();
}
void CTransform3::ShearX(double b, double c)
{
Identity();
M[0][1] = b;
M[0][2] = c;
MultiplyMatrix();
}
void CTransform3::ShearY(double d, double f)
{
Identity();
M[1][0] = d;
M[1][2] = f;
MultiplyMatrix();
}
void CTransform3::ShearZ(double g, double h)
{
Identity();
M[2][0] = g;
M[2][1] = h;
MultiplyMatrix();
}
void CTransform3::MultiplyMatrix(void)
{
CP3* PTemp = new CP3[ptNumber];
for (int i = 0; i < ptNumber; i++)
{
PTemp[i] = P[i];
}
for (int i = 0; i < ptNumber; i++)
{
P[i].x = M[0][0] * PTemp[i].x + M[0][1] * PTemp[i].y + M[0][2] * PTemp[i].z + M[0][3] * PTemp[i].w;
P[i].y = M[1][0] * PTemp[i].x + M[1][1] * PTemp[i].y + M[1][2] * PTemp[i].z + M[1][3] * PTemp[i].w;
P[i].z = M[2][0] * PTemp[i].x + M[2][1] * PTemp[i].y + M[2][2] * PTemp[i].z + M[2][3] * PTemp[i].w;
P[i].w = M[3][0] * PTemp[i].x + M[3][1] * PTemp[i].y + M[3][2] * PTemp[i].z + M[3][3] * PTemp[i].w;
}
delete[]PTemp;
}
定义投影类Projection
#pragma once
#include"P3.h"
#include<math.h>
#define PI 3.141659265
class CProjection
{
public:
CProjection(void);
virtual ~CProjection(void);
void SetEye(double R);
void SetEye(double Phi, double Psi, double R, double d);
void SetEye(double Phi, double Psi, double R);
void SetEye(double Phi, double Psi);
void InitialParameter(void);
CP2 OrthogonalProjection(CP3 WorldPoint);
CP2 ObliqueProjection(CP3 WorldPoint);
CP2 PerspectiveProjection(CP3 WorldPoint);
public:
CP3 EyePoint;
private:
double k[8];
double R, d, Phi, Psi;
};
#include "pch.h"
#include "Projection.h"
CProjection::CProjection(void)
{
R = 1200, d = 800;
Phi = 90.0, Psi = 0.0;
InitialParameter();
}
CProjection::~CProjection(void)
{
}
void CProjection::SetEye(double R)
{
EyePoint.z = R;
}
void CProjection::SetEye(double Phi, double Psi, double R, double d)
{
this->Phi = Phi;
this->Psi = Psi;
this->R = R;
this->d = d;
}
void CProjection::SetEye(double Phi, double Psi, double R)
{
this->Phi = Phi;
this->Psi = Psi;
this->R = R;
}
void CProjection::SetEye(double Phi, double Psi)
{
this->Phi = Phi;
this->Psi = Psi;
}
void CProjection::InitialParameter(void)
{
k[0] = sin(PI * Phi / 180);
k[1] = cos(PI * Phi / 180);
k[2] = sin(PI * Psi / 180);
k[3] = cos(PI * Psi / 180);
k[4] = k[0] * k[2];
k[5] = k[0] * k[3];
k[6] = k[1] * k[2];
k[7] = k[1] * k[3];
EyePoint.x = k[4] * R;
EyePoint.y = k[1] * R;
EyePoint.z = k[5] * R;
}
CP2 CProjection::OrthogonalProjection(CP3 WorldPoint)
{
CP2 ScreenPoint;
ScreenPoint.x = WorldPoint.x;
ScreenPoint.y = WorldPoint.y;
return ScreenPoint;
}
CP2 CProjection::ObliqueProjection(CP3 WorldPoint)
{
CP2 ScreenPoint;
double Cota = 0.5;
double Beta = PI / 4;
ScreenPoint.x = WorldPoint.x - WorldPoint.z * Cota * cos(Beta);
ScreenPoint.y = WorldPoint.y - WorldPoint.z * Cota * cos(Beta);
return ScreenPoint;
}
CP2 CProjection::PerspectiveProjection(CP3 WorldPoint)
{
CP3 ViewPoint;
ViewPoint.x = k[3] * WorldPoint.x - k[2] * WorldPoint.z;
ViewPoint.y = -k[6] * WorldPoint.x + k[0] * WorldPoint.y - k[7] * WorldPoint.z;
ViewPoint.z = -k[4] * WorldPoint.x - k[1] * WorldPoint.y - k[5] * WorldPoint.z + R;
CP2 ScreenPoint;
ScreenPoint.x = d * ViewPoint.x / ViewPoint.z;
ScreenPoint.y = d * ViewPoint.y / ViewPoint.z;
return ScreenPoint;
}
定义立方体类CCube
#include"P2.h"
#include"Projection.h"
#define ROUND(d) int(d+0.5)
class CCube
{
public:
CCube(void);
virtual ~CCube(void);
void ReadPoint(void);
void ReadFacet(void);
CP3* GetVertexArrayName(void);
void Draw(CDC* pDC);
void Draw2(CDC* pDC);
void Draw3(CDC* pDC);
public:
CProjection projection;
private:
CP3 P[8];
CFacet F[6];
};
#include "pch.h"
#include "Cube.h"
CCube::CCube(void)
{
projection.InitialParameter();
}
CCube::~CCube(void)
{
}
void CCube::ReadPoint(void)
{
P[0].x = 0, P[0].y = 0, P[0].z = 0;
P[1].x = 1, P[1].y = 0, P[1].z = 0;
P[2].x = 1, P[2].y = 1, P[2].z = 0;
P[3].x = 0, P[3].y = 1, P[3].z = 0;
P[4].x = 0, P[4].y = 0, P[4].z = 1;
P[5].x = 1, P[5].y = 0, P[5].z = 1;
P[6].x = 1, P[6].y = 1, P[6].z = 1;
P[7].x = 0, P[7].y = 1, P[7].z = 1;
}
void CCube::ReadFacet(void)
{
F[0].Index[0] = 4; F[0].Index[1] = 5; F[0].Index[2] = 6; F[0].Index[3] = 7;
F[1].Index[0] = 0; F[1].Index[1] = 3; F[1].Index[2] = 2; F[1].Index[3] = 1;
F[2].Index[0] = 0; F[2].Index[1] = 4; F[2].Index[2] = 7; F[2].Index[3] = 3;
F[3].Index[0] = 1; F[3].Index[1] = 2; F[3].Index[2] = 6; F[3].Index[3] = 5;
F[4].Index[0] = 2; F[4].Index[1] = 3; F[4].Index[2] = 7; F[4].Index[3] = 6;
F[5].Index[0] = 0; F[5].Index[1] = 1; F[5].Index[2] = 5; F[5].Index[3] = 4;
}
CP3* CCube::GetVertexArrayName(void)
{
return P;
}
void CCube::Draw(CDC* pDC)
{
CP2 ScreenPoint, temp;
for (int nFacet = 0; nFacet < 6; nFacet++)
{
for (int nPoint = 0; nPoint < 4; nPoint++)
{
ScreenPoint = projection.OrthogonalProjection(P[F[nFacet].Index[nPoint]]);
if (0 == nPoint)
{
pDC->MoveTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
temp = ScreenPoint;
}
else
{
pDC->LineTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
}
}
pDC->LineTo(ROUND(temp.x), ROUND(temp.y));
}
}
void CCube::Draw2(CDC* pDC)
{
CP2 ScreenPoint, temp;
for (int nFacet = 0; nFacet < 6; nFacet++)
{
for (int nPoint = 0; nPoint < 4; nPoint++)
{
ScreenPoint = projection.ObliqueProjection(P[F[nFacet].Index[nPoint]]);
if (0 == nPoint)
{
pDC->MoveTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
temp = ScreenPoint;
}
else
{
pDC->LineTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
}
}
pDC->LineTo(ROUND(temp.x), ROUND(temp.y));
}
}
void CCube::Draw3(CDC* pDC)
{
CP2 ScreenPoint, temp;
for (int nFacet = 0; nFacet < 6; nFacet++)
{
for (int nPoint = 0; nPoint < 4; nPoint++)
{
ScreenPoint = projection.PerspectiveProjection(P[F[nFacet].Index[nPoint]]);
if (0 == nPoint)
{
pDC->MoveTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
temp = ScreenPoint;
}
else
{
pDC->LineTo(ROUND(ScreenPoint.x), ROUND(ScreenPoint.y));
}
}
pDC->LineTo(ROUND(temp.x), ROUND(temp.y));
}
}
testview
// 操作
public:
void DrawObject(CDC* pDC);
void DoubleBuffer(CDC* pDC);//双缓冲
enum class ProjectionType
{
PerspectiveProjection, ObliqueProjection, OrthogonalProjection, ViewTransform1, ViewTransform2
}m_ProjectionType;//用于菜单控制
//声明所需变量
protected:
CTransform3 transform;
CCube cube;
double Alpha, Beta;
double Phi, Psi;
double R, d;
BOOL bPlay;
变量初始化
CTest4View::CTest4View() noexcept
{
// TODO: 在此处添加构造代码
R = 1200, d = 800;
Phi =45.0, Psi = 45.0;
Alpha = 0.0, Beta = 0.0;
bPlay = FALSE;
m_ProjectionType = ProjectionType::OrthogonalProjection;
cube.projection.SetEye(Phi, Psi, R, d);
cube.ReadPoint();
cube.ReadFacet();
transform.SetMatrix(cube.GetVertexArrayName(), 8);
double nEdge = 100;
transform.Scale(nEdge, nEdge, nEdge);
transform.Translate(-nEdge / 2, -nEdge / 2, -nEdge / 2);
}
DrawObject
void CTest4View::DrawObject(CDC* pDC)
{
if (m_ProjectionType == ProjectionType::OrthogonalProjection) {
cube.Draw(pDC);
}
else if (m_ProjectionType == ProjectionType::ObliqueProjection) {
cude.Draw2(pDC);
}
else
{
cube.Draw3(pDC);
}
}
DoubleBuffer
void CTest4View::DoubleBuffer(CDC* pDC)
{
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);
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap NewBitmap, * pOldBitmap;
NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = memDC.SelectObject(&NewBitmap);
memDC.FillSolidRect(rect, pDC->GetBkColor());
rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);
memDC.SetMapMode(MM_ANISOTROPIC);
memDC.SetWindowExt(rect.Width(), rect.Height());
memDC.SetViewportExt(rect.Width(), -rect.Height());
memDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
DrawObject(&memDC);
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);
memDC.SelectObject(pOldBitmap);
NewBitmap.DeleteObject();
}
OnDraw
void CTest4View::OnDraw(CDC* pDC)
{
CTest4Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
DoubleBuffer(pDC);
}
菜单控制
void CTest4View::OnOrthogonalProjection()
{
// TODO: 在此添加命令处理程序代码
m_ProjectionType = ProjectionType::OrthogonalProjection;
}
void CTest4View::OnObliqueProjection()
{
// TODO: 在此添加命令处理程序代码
m_ProjectionType = ProjectionType::ObliqueProjection;
}
void CTest4View::OnPerspectiveProjection()
{
// TODO: 在此添加命令处理程序代码
m_ProjectionType = ProjectionType::PerspectiveProjection;
}
void CTest4View::OnViewTransform1()
{
// TODO: 在此添加命令处理程序代码
m_ProjectionType = ProjectionType::ViewTransform1;
}
void CTest4View::OnViewTransform2()
{
// TODO: 在此添加命令处理程序代码
m_ProjectionType = ProjectionType::ViewTransform2;
}
键盘响应事件
void CTest4View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (!bPlay)
{
if (m_ProjectionType == ProjectionType::ViewTransform1)
{
switch (nChar)
{
case VK_UP: {
R += 50;
cube.projection.SetEye(Phi, Psi, R, d);
break;
}
case VK_DOWN: {
R -= 50;
cube.projection.SetEye(Phi, Psi, R, d);
break;
}
default: {
break; }
}
Invalidate(FALSE);
}
else if(m_ProjectionType == ProjectionType::ViewTransform2)
{
switch (nChar)
{
case VK_UP: {
Phi += 5;
cube.projection.SetEye(Phi, Psi);
cube.projection.InitialParameter();
break;
}
case VK_DOWN: {
Phi -= 5;
cube.projection.SetEye(Phi, Psi);
cube.projection.InitialParameter();
break;
}
case VK_LEFT: {
Psi += 5;
cube.projection.SetEye(Phi, Psi);
cube.projection.InitialParameter();
break;
}
case VK_RIGHT: {
Psi -= 5;
cube.projection.SetEye(Phi, Psi);
cube.projection.InitialParameter();
break;
}
default: {
break; }
}
Invalidate(FALSE);
}
else
{
switch (nChar)
{
case VK_UP: {
Alpha = -5;
transform.RotateX(Alpha);
break;
}
case VK_DOWN: {
Alpha = +5;
transform.RotateX(Alpha);
break;
}
case VK_LEFT: {
Beta = -5;
transform.RotateY(Beta);
break;
}
case VK_RIGHT: {
Beta = +5;
transform.RotateY(Beta);
break;
}
default: {
break; }
}
Invalidate(FALSE);
}
}
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}