方块旋转动态
2018-8-11 ~ 2021-3-7
(2)
这个程序展示了一组旋转立方体构成的动态图像。
完整源代码如下:
// 项目名称 方块旋转动态
// 作者 星羽1704
// email 1479245050@qq.com
// 联系方式 qq 1479245050
// 描述 将三维空间的点投影到二维平面,感受三维正方体的旋转的视觉盛宴
// 暂时做到这点,以后要修改的话,应该是2019年的6月了。
// 编译环境 win10 64位 + vs2017 + easyx—ver: 20180727(beta)
//
#include <graphics.h>
#include <math.h>
#define Db_x 640
#define Db_y 640
#define center_x Db_x/2
#define center_y Db_y/2
#define square_root_two 1.4142135623731
#define square_root_three 1.7320508075689
#define square_root_six 2.4494897427832
#define PI 3.1415926535898
#define cubenum 29 // 正方体数量
#define LineCOLOR BLACK
#define bkCOLOR WHITE
#define turnrate 3 // 正方体之间旋转等待
#define Stardelay 800
#define Enddelay 1000
#define FPS 50 // 帧数
#define sidegap 8 // 正方体边差
///////////////////////
// 结构定义
// 定义三维点
class POINT3D
{
public:
double x, y, z;
POINT3D() {}
POINT3D(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
POINT3D(POINT3D &P) {
x = P.x;
y = P.y;
z = P.z;
}
private:
};
// 定义正方体
struct Cube
{
double side_length; // 边长
POINT3D P[8]; // 当前坐标
POINT3D tP[8]; // 初始坐标
POINT p[8]; // 投影坐标
int taking; // 是否在可以运动 0否1是 初始为1 运动结束为0
int shoptime; // 暂停时间
int haddone; // 已完成帧数,到 FPS值 停止 taking变为0
}cube[cubenum]; // cubenum个 边长低为10 公差10
int end; // 0为初始值,所有正方体停止后end变为1
int temp; // 临时变量,可以随便用
///////////////////////
// 函数声明
// 功能函数
POINT projection(POINT3D &P3); // 降维投影得到起始二维坐标
// 过程函数
void Initcube(); // 初始化所有正方体信息
void rotation(); // 旋转
void Drawcube(); // 描点连线
void changing(); // 计算二维点
void ifend(); // 判断是否结束
///////////////////////
// 函数定义
int main()
{
// 设置画布相关信息
initgraph(Db_x, Db_y);
setbkcolor(bkCOLOR);
setbkmode(TRANSPARENT);
setlinecolor(BLACK);
BeginBatchDraw();
while (true)
{
cleardevice();
Initcube();
// 静态输出
Drawcube();
FlushBatchDraw();
Sleep(Stardelay);
// 开始动画
while (end == 0)
{
cleardevice();
rotation();
changing();
Drawcube();
FlushBatchDraw();
ifend();
Sleep(1000 / FPS); // 1000/帧数 = 延迟时间
}
Sleep(Enddelay);
}
EndBatchDraw();
closegraph();
return 0;
}
// 初始化所有正方体信息
void Initcube()
{
end = 0;
for (int num = 0; num < cubenum; num++)
{
// 设置边长
cube[num].side_length = square_root_two * (num + 1) * sidegap;
// 设置三维点
cube[num].tP[0] = { 0,0,0 };
cube[num].tP[1] = { cube[num].side_length / square_root_two ,
cube[num].side_length / square_root_two ,
0 };
cube[num].tP[2] = { 0,
cube[num].side_length * square_root_two ,
0 };
cube[num].tP[3] = { cube[num].side_length / square_root_two * (-1) ,
cube[num].side_length / square_root_two ,
0 };
for (int num1 = 4; num1 < 9; num1++)
{
cube[num].P[(num1 - 4)] = cube[num].tP[(num1 - 4)];
cube[num].tP[num1] = { cube[num].P[(num1 - 4)].x ,cube[num].P[(num1 - 4)].y ,
cube[num].P[(num1 - 4)].z + cube[num].side_length };
cube[num].P[num1] = cube[num].tP[num1];
}
cube[num].taking = 1;
cube[num].shoptime = (int)(num * turnrate);
cube[num].haddone = 0;
}
// 转换得到投影点
changing();
}
// 旋转
void rotation()
{
// 旋转轴点为(0,cube[num].side_length / square_root_two,z)
for (int num = 0; num < cubenum; num++)
{
if (cube[num].taking == 1)
{
if (cube[num].shoptime == 0)
{
// 底面做旋转操作
for (int num1 = 0; num1 < 4; num1++)
{
cube[num].P[num1].x = (cube[num].tP[num1].x - 0) * cos(-cube[num].haddone*PI / FPS) - (cube[num].tP[num1].y - cube[num].side_length / square_root_two)*sin(-cube[num].haddone*PI / FPS) + 0;
cube[num].P[num1].y = (cube[num].tP[num1].x - 0) * sin(-cube[num].haddone*PI / FPS) + (cube[num].tP[num1].y - cube[num].side_length / square_root_two)*cos(-cube[num].haddone*PI / FPS) + cube[num].side_length / square_root_two;
}
// 顶面
for (int num2 = 4; num2 < 8; num2++)
{
cube[num].P[num2].x = cube[num].P[(num2 - 4)].x;
cube[num].P[num2].y = cube[num].P[(num2 - 4)].y;
cube[num].P[num2].z = cube[num].P[(num2 - 4)].z + cube[num].side_length;
}
cube[num].haddone++;
if (cube[num].haddone == (FPS + 1))
cube[num].taking = 0;
}
else cube[num].shoptime--;
}
}
}
// 计算二维点
void changing()
{
for (int num = 0; num < cubenum; num++)
for (int num1 = 0; num1 < 8; num1++)
cube[num].p[num1] = projection(cube[num].P[num1]);
}
// 描点连线
void Drawcube()
{
for (int num = 0; num < cubenum; num++)
{
for (int num1 = 0; num1 < 4; num1++)
{
// 底层
temp = ((num1 + 1) == 4) ? 0 : (num1 + 1);
line(cube[num].p[num1].x, cube[num].p[num1].y, cube[num].p[temp].x, cube[num].p[temp].y);
// 侧楞
temp = num1 + 4;
line(cube[num].p[num1].x, cube[num].p[num1].y, cube[num].p[temp].x, cube[num].p[temp].y);
// 顶层
temp = ((num1 + 5) == 8) ? 4 : (num1 + 5);
line(cube[num].p[(num1 + 4)].x, cube[num].p[(num1 + 4)].y, cube[num].p[temp].x, cube[num].p[temp].y);
}
}
}
// 判断是否结束
void ifend()
{
if (cube[(cubenum - 1)].taking == 0)
end = 1;
}
// 投影得到起始二维坐标
POINT projection(POINT3D &p3)
{
POINT p2;
// x直接取值
p2.x = (long)p3.x + center_x;
// y用点到直线公式
p2.y = (long)((p3.y * square_root_two - p3.z * 2) / square_root_six + center_y);
return p2;
}