MATLAB画三维动态魔方/旋转魔方/旋转立方体

Posted 嗑药的皮皮虾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MATLAB画三维动态魔方/旋转魔方/旋转立方体相关的知识,希望对你有一定的参考价值。

以下是我的思路

先了解几个重要的函数

patch()函数

原理:点按顺序连成封闭多边形。

使用:

point_sequence=[1,2,3,4]; %点连接的顺序
square_xyz=[3,1,3;1,1,3;1,-1,3;3,-1,3]; %三维坐标4x3矩阵
patch('Faces',point_sequence,'Vertices',square_xyz,'FaceColor','blue');
axis([-3,3,-3,3,-3,3]);%坐标系范围
view(3);

rotx()、roty()、rotz()函数

作用:生成三阶旋转矩阵,例如点A以x为轴逆时针旋转90°得到点B,旋转矩阵为Q,则B=QA,A,B为列向量。rotx(theta);%theta为逆时针旋转角度

使用:

A = [1,1,1]';
Q=rotx(90);
B=Q*A

>>B =
     1
    -1
     1

如何实现旋转

用patch()函数生成patch对象句柄,用句柄查看patch对象的属性,使用get()函数获取坐标属性值,使用set()函数重新设置坐标矩阵从而实现旋转。

例如将蓝色正方形绕x轴旋转45°,程序如下:

point_sequence=[1,2,3,4]; %点连接的顺序
square_xyz=[3,1,3;1,1,3;1,-1,3;3,-1,3]; %三维坐标4x3矩阵,行向量坐标

axis([-3,3,-3,3,-3,3]);%坐标系范围
xlabel('X');
ylabel('Y');
zlabel('Z');
view(3);%三维视角
patch_handles=patch('Faces',point_sequence,'Vertices',square_xyz,'FaceColor','blue');
Vertices=get(patch_handles,'Vertices') %得到三维坐标4x3矩阵,行向量坐标
R = rotx(45); %绕x轴旋转45°生成旋转矩阵
Vertices = (R*Vertices')'; %得到旋转后的矩阵
pause(1); %暂停1秒
set(patch_handles,'Vertices',Vertices); %设置坐标矩阵

效果:

确定三维坐标

如何确定魔方6个面共54个色卡,每个色块4个顶点的坐标呢?如果一个一个点确定坐标,然后得到一个一个色块的4x3矩阵(行向量),工程量太大也容易出错,而且不易修改尺寸,这里我提供一个方法。

以魔方的正中心为原点(0,0,0),通过单轴坐标平移得到6个面的中心点坐标,取一个面的中心点坐标通过双轴坐标平移得到每个色块的中心点坐标,再取一个色块的中心点坐标通过双轴坐标平移得到色块4个顶点的坐标。双轴坐标平移都是有规律的。

取一个色块边长为2个单位,因为是双轴坐标平移有一个坐标轴是不变的,所以下面这两个全局变量是4x2矩阵(行向量)。

global anticlockwise_4point_xyxzyz %逆时针4个点,逆时针即夹角增大的方向
anticlockwise_4point_xyxzyz=[1,1;-1,1;-1,-1;1,-1];
global anticlockwise_9point_xyxzyz %逆时针9个点,最后一个坐标原点
anticlockwise_9point_xyxzyz=[2,0;2,2;0,2;-2,2;-2,0;-2,-2;0,-2;2,-2;0,0];

编写3个函数

函数一:一个中心点生成9个中心点

%双轴坐标平移,得到每个面的9个中心点,最后一个是中心块的坐标
function central_9point_xyz=get_central_9point_xyz_fun(xyz_axis) 
global anticlockwise_9point_xyxzyz;
temp=anticlockwise_9point_xyxzyz;
central_9point_xyz=ones(9,3).*3;%原点(0,0,0)向某个轴正方向移动3个单位
switch xyz_axis
    case '+x' %垂直+x轴的面上的点坐标平移
        central_9point_xyz(:,2:3)=temp;
    case '-x'
        central_9point_xyz=-central_9point_xyz; %负方向移动3个单位
        central_9point_xyz(:,2:3)=temp;        
    case '+y'
        central_9point_xyz(:,1)=temp(:,1);
        central_9point_xyz(:,3)=temp(:,2);
    case '-y'
        central_9point_xyz=-central_9point_xyz;
        central_9point_xyz(:,1)=temp(:,1);
        central_9point_xyz(:,3)=temp(:,2);
    case '+z'
        central_9point_xyz(:,1:2)=temp;
    case '-z'
        central_9point_xyz=-central_9point_xyz;
        central_9point_xyz(:,1:2)=temp;       
end
end

 函数二:一个中心点生成色块4个顶点

%双轴坐标平移,一个色块的中心点得到色块4个顶点
function square_4point_xyz=get_square_4point_xyz_fun(xyz_axis,central_point_xyz) 
global anticlockwise_4point_xyxzyz
temp=anticlockwise_4point_xyxzyz;
increment=central_point_xyz; %中心点为偏移量
square_4point_xyz=zeros(4,3); %色块的坐标矩阵
switch xyz_axis
    case '+x'
        square_4point_xyz(:,2:3)=temp;
    case '-x'
        square_4point_xyz=-square_4point_xyz;
        square_4point_xyz(:,2:3)=temp;        
    case '+y'
        square_4point_xyz(:,1)=temp(:,1);
        square_4point_xyz(:,3)=temp(:,2);
    case '-y'
        square_4point_xyz=-square_4point_xyz;
        square_4point_xyz(:,1)=temp(:,1);
        square_4point_xyz(:,3)=temp(:,2);
    case '+z'
        square_4point_xyz(:,1:2)=temp;
    case '-z'
        square_4point_xyz=-square_4point_xyz;
        square_4point_xyz(:,1:2)=temp;       
end
for i=1:4 
    square_4point_xyz(i,:)=square_4point_xyz(i,:)+increment; %每个点加上偏移量
end
end

 函数三:拼成36x3阶矩阵(行向量),包含一个面9个色块的顶点坐标,调用了函数二

%得到一个面九个色块顶点的坐标,36x3阶矩阵(行向量)
function face_9square_xyz=get_face_9square_xyz_fun(xyz_axis,face_central_9point_xyz) 
face_9square_xyz=zeros(36,3);
for i=1:9
    face_9square_xyz((i-1)*4+1:i*4,:)=get_square_4point_xyz_fun(xyz_axis,face_central_9point_xyz(i,:));   
end
end

 旋转魔方一个面的思路

1、句柄

前面举例说了修改patch句柄的'Vertices'属性即顶点坐标可实现色块的移动,可以用一维数组patch_handles存储54个色块的54个句柄,用patch()函数生成句柄,第一个色块的句柄就是patch_handles(1)=patch()。patch_handles为全局变量。

global patch_handles %patch对象句柄
patch_handles=[];

patch_handles(1)=patch('Faces',point_sequence,'Vertices',Uface_9square_xyz(1:4,:),'FaceColor',Uface_color);

2、找要旋转色块句柄的索引

流程为:

确定色块所在平面垂直的坐标轴,如x正半轴表示为'+x'。下面以'+x'为例

用get()函数获取色块句柄的'XData'属性得到四个顶点的x坐标组成的列向量xyz

用find()函数判断列向量xyz中是否存在等于3的元素,因为垂直正半x轴面上的点的x轴坐标必=3

记下索引存储到index数组中

函数如下返回值为索引数组index:

function index=get_index_fun(xyz_axes) %找要旋转色块句柄的索引
global patch_handles
index=[];
XYZData_str='';
compare=0;
switch xyz_axes
    case '+x'
        XYZData_str='XData';
        compare=3;
    case '-x'
        XYZData_str='XData';
        compare=-3;
    case '+y'
        XYZData_str='YData';
        compare=3;
    case '-y'
        XYZData_str='YData';
        compare=-3;
    case '+z'
        XYZData_str='ZData';
        compare=3;
    case '-z'
        XYZData_str='ZData';
        compare=-3;
end
for i=1:54   
    xyz=get(patch_handles(i),XYZData_str);
    f=find(xyz==compare);
    if ~isempty(f)
        index=[index,i];
    end
    if length(index)==21
        break;
    end
end
end

3、设置句柄属性实现旋转

要注意坐标矩阵V与旋转矩阵R相乘后可能出现分数,就不能用某个轴坐标等于3或-3判断色块所在面,需使用四舍五入取整函数对坐标矩阵取整,应该在最后一轮设置坐标属性时取整,因为旋转90°分为9次每次旋转10°实现动态旋转,应该在第9次时对坐标矩阵四舍五入取整,取整早了魔方会缩小。

函数如下:

function rotation_90(xyz_axes,direction) %旋转在xyz_axes轴上的面90°并画色块
global patch_handles
index=get_index_fun(xyz_axes);
L=length(index); %需要旋转21个色块
per_degree=10; %每次旋转10°
time=9; %一共旋转9次
switch xyz_axes
    case '+x'
        R=rotx(per_degree*direction); %绕x轴旋转生成的旋转矩阵R
    case '-x'
        R=rotx(per_degree*direction);
    case '+y'
        R=roty(per_degree*direction);
    case '-y'
        R=roty(per_degree*direction);
    case '+z'
        R=rotz(per_degree*direction);
    case '-z'
        R=rotz(per_degree*direction);
end
for t=1:time-1
    for i=1:L
        V=get(patch_handles(index(i)),'Vertices');%获得4x3坐标矩阵
        V=(R*V')'; %得到旋转后的矩阵
        set(patch_handles(index(i)),'Vertices',V); %画色块
    end
    pause(0.1);
end
%最后一次旋转坐标四舍五入取整
for i=1:L
    V=get(patch_handles(index(i)),'Vertices');%获得4x3坐标矩阵
    V=(R*V')'; %得到旋转后的矩阵
    V=round(V); %非常重要,四舍五入取整
    set(patch_handles(index(i)),'Vertices',V); %画色块
end
end

主函数和运行效果

以下是部分主函数,很多重复的没有贴出来,例如给patch_handles赋值54个句柄。 

clc;
clear;
global patch_handles %patch对象句柄
patch_handles=[];
global point_sequence
point_sequence=[1,2,3,4];
global anticlockwise_4point_xyxzyz %逆时针4个点
anticlockwise_4point_xyxzyz=[1,1;-1,1;-1,-1;1,-1];
global anticlockwise_9point_xyxzyz %逆时针9个点,逆时针即夹角增大的方向
anticlockwise_9point_xyxzyz=[2,0;2,2;0,2;-2,2;-2,0;-2,-2;0,-2;2,-2;0,0];%逆时针8个中心点,加一个(0,0)点
%六个面颜色
Uface_color='y';
Dface_color='w';
Fface_color='b';
Bface_color='g';
Lface_color=[1,0.5,0];%橙色
Rface_color='r';

Uface_central_9point_xyz=get_central_9point_xyz_fun('+z'); %F面9个中心点的坐标
Uface_9square_xyz=get_face_9square_xyz_fun('+z',Uface_central_9point_xyz);

axis([-5,5,-5,5,-5,5]);%坐标系范围
title('魔方');
axis off
view(3);%三维视角

patch_handles(1)=patch('Faces',point_sequence,'Vertices',Uface_9square_xyz(1:4,:),'FaceColor',Uface_color);

pause(1);
rotation_90('+x',1);
rotation_90('+z',-1);
rotation_90('+y',1);
rotation_90('+y',-1);
rotation_90('+z',1);
rotation_90('+x',-1);

结尾

你可以根据我的思路自己写一个,以上就是全部函数没有漏的。或者另辟蹊径。

下一篇文章:给魔方加一个GUI操作界面

http://t.csdn.cn/yk9wDhttp://t.csdn.cn/yk9wD

原创不易还请支持

https://download.csdn.net/download/qq_42053235/85240749https://download.csdn.net/download/qq_42053235/85240749

以上是关于MATLAB画三维动态魔方/旋转魔方/旋转立方体的主要内容,如果未能解决你的问题,请参考以下文章

基于MATLAB GUI的魔方三维动态还原仿真程序

基于MATLAB GUI的魔方三维动态还原仿真程序

基于MATLAB GUI的魔方三维动态还原仿真程序

魔方 Unity 5 [关闭]

用CSS代码做出一个简单的自动旋转正方体(css魔方原理)

用CSS代码做出一个简单的自动旋转正方体(css魔方原理)