//实验名称:带有线消隐的三维物体投影绘制
//功 能:对于用户输入的三维物体空间信息与选择的投影面(三个坐标面之一),绘制该三维物体在该投影面上的带消隐的投影图
//编译环境:Visual Studio 2022,EasyX_20220116
#include<iostream>
#include<graphics.h>
#include<conio.h>
#include<vector>
using namespace std;
//定义一个结构体表示面表的结点,结点中存储该面所对应的开始结点和结束结点在边表中的下标
struct Face
{
unsigned start = 0;
unsigned end = 0;
};
//定义一个点类表示三维坐标系中的坐标点,并定义一个构造函数
struct Point
{
int x;
int y;
int z;
explicit Point(const int& x = 0, const int& y = 0, const int& z = 0) :x(x), y(y), z(z) {}
};
//消隐投影的主要函数,可以处理不同的三维物体在三个坐标面上的投影图,因此是一个通用函数
void Blanking(void)
{
//由用户输入的多面体面数创立一个边表
unsigned FaceNum;
cout << "请输入该多面体的面数:";
cin >> FaceNum;
Face* FaceArray = new Face[FaceNum];
//由用户输入的多面体顶点数创立一个顶点表,用于存储多面体的每一个顶点
unsigned PointNum;
cout << "请输入多面体的顶点数:";
cin >> PointNum;
Point* PointArray = new Point[PointNum];
cout << "请分别输入这些顶点的空间坐标(x,y,z)" << endl;
for (unsigned i = 0; i < PointNum; i++)
{
cin >> PointArray[i].x >> PointArray[i].y >> PointArray[i].z;
}
//输出一次点表,方便用户在后续步骤中找出对应点的下标
cout << "各个顶点及其对应下标如下所示:" << endl;
for (unsigned i = 0; i < PointNum; i++)
{
cout << "下标: " << i << "\t 坐标: " << PointArray[i].x << " " << PointArray[i].y << " " << PointArray[i].z << endl;
}
//由于事先难以确定边的总数,因此考虑用向量vector代替数组来表示边表,边表中存储边所对应的点在点表中的下标
vector<int>SideArray;
for (unsigned i = 0; i < FaceNum; i++)
{
FaceArray[i].start = SideArray.size();
unsigned SideNum;
cout << "请输入第" << i + 1 << "个面的边数:";
cin >> SideNum;
cout << "请按照顺序输入构成这些边的顶点在顶点表中的下标:";
for (unsigned j = 0; j < SideNum; j++)
{
unsigned pos;
cin >> pos;
SideArray.push_back(pos);
}
FaceArray[i].end = SideArray.size() - 1;
}
//到此为止,三个表:点表、边表和面表都创建完成并完成了初始化工作
int ProjectionFace;
//由用户选择想要的消隐投影面
cout << "单链三表结构建立完成,请选择投影面(1表示xOz面,2表示yOz面,3表示xOy面):";
cin >> ProjectionFace;
initgraph(1000, 700);
//进行一次坐标系转换,由于计算机中的坐标系的原点在屏幕左上角且纵轴方向与数学中纵轴方向相反,因此进行转换,并在画布上绘制出坐标轴
line(0, 350, 1000, 350);
line(500, 0, 500, 700);
setcolor(RED);
if (ProjectionFace == 1)//第一种情况,投影面为xOz面
{
for (unsigned i = 0; i < FaceNum; i++)
{
//由于投影面为xOz面,因此纵坐标可以忽略不计,先从点表中取出该面对应的所有点
int x1 = PointArray[SideArray[FaceArray[i].start]].x;
int z1 = PointArray[SideArray[FaceArray[i].start]].z;
int x2 = PointArray[SideArray[FaceArray[i].start + 1]].x;
int z2 = PointArray[SideArray[FaceArray[i].start + 1]].z;
int x3 = PointArray[SideArray[FaceArray[i].start + 2]].x;
int z3 = PointArray[SideArray[FaceArray[i].start + 2]].z;
//计算判定值,由判定值的正负即可确定该面对于观察者是否可见
int Eflag = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
if (Eflag > 0)//如果判定值大于零,说明该面对于观察者可见,进行如下操作
{
unsigned PointN = FaceArray[i].end - FaceArray[i].start + 1;
POINT* p = new POINT[PointN];
//对该面上的点进行投影操作,并转换坐标系
for (unsigned j = FaceArray[i].start; j <= FaceArray[i].end; j++)
{
p[j - FaceArray[i].start].x = PointArray[SideArray[j]].x + 500;
p[j - FaceArray[i].start].y = 350 - PointArray[SideArray[j]].z;
}
//求出投影点后按照原有的拓扑关系对点进行连线操作
for (unsigned j = 0; j < PointN - 1; j++)
{
line(p[j].x, p[j].y, p[j + 1].x, p[j + 1].y);
}
line(p[PointN - 1].x, p[PointN - 1].y, p[0].x, p[0].y);
}
}
_getch();
}
else if (ProjectionFace == 2)//第二种情况,投影面为yOz面,操作方法与之前类似
{
for (unsigned i = 0; i < FaceNum; i++)
{
int y1 = PointArray[SideArray[FaceArray[i].start]].y;
int z1 = PointArray[SideArray[FaceArray[i].start]].z;
int y2 = PointArray[SideArray[FaceArray[i].start + 1]].y;
int z2 = PointArray[SideArray[FaceArray[i].start + 1]].z;
int y3 = PointArray[SideArray[FaceArray[i].start + 2]].y;
int z3 = PointArray[SideArray[FaceArray[i].start + 2]].z;
int Eflag = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
if (Eflag > 0)
{
unsigned PointN = FaceArray[i].end - FaceArray[i].start + 1;
POINT* p = new POINT[PointN];
for (unsigned j = FaceArray[i].start; j <= FaceArray[i].end; j++)
{
p[j - FaceArray[i].start].x = PointArray[SideArray[j]].y + 500;
p[j - FaceArray[i].start].y = 350 - PointArray[SideArray[j]].z;
};
for (unsigned j = 0; j < PointN - 1; j++)
{
line(p[j].x, p[j].y, p[j + 1].x, p[j + 1].y);
}
line(p[PointN - 1].x, p[PointN - 1].y, p[0].x, p[0].y);
}
}
_getch();
}
else if (ProjectionFace == 3)//第三种情况,投影面为xOy面,操作方法与之前类似
{
for (unsigned i = 0; i < FaceNum; i++)
{
int x1 = PointArray[SideArray[FaceArray[i].start]].x;
int y1 = PointArray[SideArray[FaceArray[i].start]].y;
int x2 = PointArray[SideArray[FaceArray[i].start + 1]].x;
int y2 = PointArray[SideArray[FaceArray[i].start + 1]].y;
int x3 = PointArray[SideArray[FaceArray[i].start + 2]].x;
int y3 = PointArray[SideArray[FaceArray[i].start + 2]].y;
int Eflag = (y2 - y1) * (x3 - x2) - (x2 - x1) * (y3 - y2);
if (Eflag > 0)
{
unsigned PointN = FaceArray[i].end - FaceArray[i].start + 1;
POINT* p = new POINT[PointN];
for (unsigned j = FaceArray[i].start; j <= FaceArray[i].end; j++)
{
p[j - FaceArray[i].start].x = PointArray[SideArray[j]].x + 500;
p[j - FaceArray[i].start].y = 350 - PointArray[SideArray[j]].y;
};
for (unsigned j = 0; j < PointN - 1; j++)
{
line(p[j].x, p[j].y, p[j + 1].x, p[j + 1].y);
}
line(p[PointN - 1].x, p[PointN - 1].y, p[0].x, p[0].y);
}
}
_getch();
}
return;
}
int main(void)
{
Blanking();
return 0;
}
凸多边形的线消隐算法(C++实现)计算机图形学作业
最新推荐文章于 2023-04-29 14:13:56 发布