四维空间的二维线框投影可视化(附matlab代码)

写这篇博客的动机是来源于Matrix67大神的一篇博客
不同维度的对话:带你进入四维世界http://www.matrix67.com/blog/archives/1323

里面有非常酷炫的展示效果。很早就想实际实践一波,但是实际动手才发现要想获得可视化效果还是不容易的。

之后查找相关的资料,发现Steven Richard Hollasch的Four-Space Visualization of 4D Objects在四维可视化部分写的非常的详细。详情可以点击http://hollasch.github.io/ray4/Four-Space_Visualization_of_4D_Objects.html。页面打不开的话,在bing上搜索这篇文章,有Cached镜像。
注意它默认用到的是左手坐标系。本文由于采用的是对称的正方体进行演示,所以用的是右手坐标系,不太影响展示效果,所以没有加以修正。

还是惯例声明:本人没有相关的工程应用经验,只是纯粹对相关算法和展示效果感兴趣才写此博客。所以如果有错误,欢迎在评论区指正,不胜感激。本文主要关注于算法的实现,对于实际应用等问题本人没有任何经验,所以也不再涉及。

1 三维空间在2维屏幕上的投影

首先常见的三维空间在2维屏幕上的投影,用来验证算法的正确性。

由于眼睛结构构造的限制,视网膜只能接受二维的光线信息。我们人类直接观察3维物体时,丢失掉垂直于视网膜方向上的维度信息,也就是物体距离眼睛的距离,或者可以叫景深。这常常被应用与某些3维游戏设计,或者一些视觉错觉方面。
当然人类也可以间接的通过两只眼睛进行距离判断,或者根据参照物,或者运动时物体相对关系,或者眼球的运动等间接因素,来感知距离。当然,这不是本文的重点。

本文拟根据相机或眼球的拍摄投影原理,进行3维空间在2维屏幕上投影的算法概述。

1.1平行投影

首先我们定义观察原点From,观测方向点To,以及定义向上方向Up。如下图所示:
在这里插入图片描述
我们的看物体的方向是从From点到To点,投影到屏幕上后,还需要定义哪里是上方,也就是从From点到Up点。

之后,求出刚才3个观察点所确定的ABC坐标系,作为眼睛坐标系。
C = T o − F r o m ∥ T o − F r o m ∥ C=\frac{To-From}{\lVert To-From \rVert} C=ToFromToFrom
A = U p × C ∥ U p × C ∥ A=\frac{Up \times C}{\lVert Up \times C \rVert} A=Up×CUp×C
B = C × A B=C \times A B=C×A
其中, ∥ X ∥ \lVert X \rVert X代表向量的2范数,或者可以叫做绝对值,它的值等于向量每个元素平方和的开根号。 C × A C \times A C×A代表向量C叉乘以向量A,得到的结果仍然是一个向量,垂直于A和C。

扫描二维码关注公众号,回复: 16063805 查看本文章

之后,真实空间中某个点的Px、Py、Pz坐标就可以转换为眼睛坐标系下的坐标P’:
P ′ = [ P x ′ P y ′ P z ′ ] = [ ( P x − F x ) ( P y − F y ) ( P z − F z ) ] ∗ [ A x B x C x A y B y C y A z B z C z ] P'=\left[ \begin{matrix} P'_x& P'_y& P'_z\\ \end{matrix} \right] \\ =\left[ \begin{matrix} (P_x-F_x)& (P_y-F_y)& (P_z-F_z)\\ \end{matrix} \right] *\left[ \begin{matrix} A_x& B_x& C_x\\ A_y& B_y& C_y\\ A_z& B_z& C_z\\ \end{matrix} \right] P=[PxPyPz]=[(PxFx)(PyFy)(PzFz)]AxAyAzBxByBzCxCyCz
上式中,Fx、Fy、Fz对应着观察点的位置,可以视为From点的坐标。公式中Ax、Ay、Az代表之前求出的A向量三个值,其余B和C向量同理。

到此,我们得到了新的空间上一点的坐标。其中P’x和P’y是在2维上的投影坐标,P’z是距离2维平面的距离。绘图时,只需要绘制P’x和P’y即可。

所以三维投影到二维算法步骤大致为:

1定义From、To、Up点
2计算对应着ABC坐标
3将实际坐标P(x,y,z)转换到眼睛坐标P'(x,y,x)
4绘制P'(x,y)作为2维投影

matlab代码如下:

%创建3维物体的二维投影(平行)
clear
clc
close all

for k=0:1:40
    
    %创建3维立方体
    Line_AB = Create_Cube(3);
    Line_AB = Line_AB*2-1;
    N=size(Line_AB,1);
    Line_List_1 = Line_AB(:,1:3)';
    Line_List_2 = Line_AB(:,4:6)';
    %旋转一定角度
    Line_List_1 = Ro_Ma_3D(2,pi/80*k)*Ro_Ma_3D(1,pi/80*k)*Line_List_1;
    Line_List_2 = Ro_Ma_3D(2,pi/80*k)*Ro_Ma_3D(1,pi/80*k)*Line_List_2;
    %定义To From Up
    To = [0,0,0];
    From = [0,0,1];
    Up = [0,1,0];
    %3D眼睛坐标
    C = (To-From)/norm(To-From);
    A = cross(C,Up)/norm(cross(C,Up));
    B = cross(A,C);
    ABC = [A',B',C'];
    %xyz坐标下的点转换
    Line_AB_ABC = zeros(size(Line_AB));
    F_xyz = [0,0,0];%定义原点,透视视角有用
    Line_ABC_1 = (Line_List_1'-ones(N,1)*F_xyz)*ABC;
    Line_ABC_2 = (Line_List_2'-ones(N,1)*F_xyz)*ABC;

    
    %投影到2D屏幕上
    figure(1)
    clf
    hold on
    for m = 1:size(Line_AB_ABC,1)
        P1 = Line_AB_ABC(m,1:2);
        P2 = Line_AB_ABC(m,4:5);
        plot([Line_ABC_1(m,1),Line_ABC_2(m,1)],[Line_ABC_1(m,2),Line_ABC_2(m,2)])
    end
    hold off
    xlim([-2,2])
    ylim([-2,2])
    pause(0.5)
end







function Line_AB = Create_Cube(Dim)
%创建Dim维度的正方体,坐标范围0-1
%Dim = 3;
Line_AB = zeros(1,2*Dim);
Line_AB(Dim+1) = 1;
Line_AB_Old = Line_AB;
for k = 2:Dim
    %向另一个维度复制
    P_Old = size(Line_AB_Old,1);%上一个维度的线数
    Line_AB_New1 = [Line_AB_Old;Line_AB_Old];
    Line_AB_New1(P_Old+1:end,k) = 1;
    Line_AB_New1(P_Old+1:end,Dim+k) = 1;
    %连接相邻维度的线
    P_Old2 = 2^(k-1);%上一个维度的点数
    Vertex2 = Full_Choose([0;1],k-1);
    Line_AB_New2 = zeros(P_Old2,2*Dim);
    Line_AB_New2(:,1:k-1) = Vertex2;
    Line_AB_New2(:,Dim+1:Dim+k-1) = Vertex2;
    Line_AB_New2(:,Dim+k) = 1;
    %汇总
    Line_AB_Old = [Line_AB_New1;Line_AB_New2];
    
end
Line_AB = Line_AB_Old;
end


function FullList=Full_Choose(n_List,n)
%全排列,可以重复
%n_List元素
%n是全排列的位数
V_Str='Xgrid';
V_Str_Sum='';
X_List=1:numel(n_List);%设置索引列表
%思路是利用ndgrid方法,实现全排列。用eval函数执行
for k=1:n
    V_Str_Sum=[V_Str_Sum,V_Str,num2str(k),','];
end
V_Str_Sum(end)=' ';
Eval_Str=['[',V_Str_Sum,']=ndgrid(','X_List',');'];
eval(Eval_Str);
V_Str_Sum2=[];
for k=n:-1:1
    V_Str_Sum2=[V_Str_Sum2,V_Str,num2str(k),'(:),'];
end
V_Str_Sum2(end)=' ';
Eval_Str=['FullList_X=[',V_Str_Sum2,'];'];
eval(Eval_Str);

FullList=n_List(FullList_X);%把生成好的列表带入到nlist中
FullList=unique(FullList,'rows');
end

function Rotation_Matrix = Ro_Ma_3D(n,theta)
%创建3D的旋转矩阵
%n=1为x轴(yz平面),n=2为y轴(xz平面),n=3为z轴(xy平面)
switch n
    case 1
        Rotation_Matrix=[1,0,0;...
            0,cos(theta),-sin(theta);...
            0,sin(theta),cos(theta)];
    case 2
        Rotation_Matrix=[cos(theta),0,sin(theta);...
            0,1,0;...
            -sin(theta),0,cos(theta)];
    case 3
        Rotation_Matrix=[cos(theta),-sin(theta),0;...
            sin(theta),cos(theta),0;...
            0,0,1];
end
end

在这里插入图片描述
注意,上图的三维效果没有用到三维绘图,纯粹是利用plot函数实现的二维投影。

1.2透视投影

透视效果表现为近大远小。下图给出了小孔成像原理下,投影后物体的大小L’和实际物体大小L的关系:
在这里插入图片描述
公式可以表示为:
L ′ h = L z \frac{L'}{h}=\frac{L}{z} hL=zL
其中h是固定不变的,投影大小L’与距离小孔的距离z成反比。

所以,简单的透视效果,可以直接将物体在ABC相机坐标系下的x和y,直接除以z即可。
x 透 视 = k x z , y 透 视 = k y z x_{透视}=k\frac{x}{z} ,y_{透视}=k\frac{y}{z} x=kzxy=kzy
其中k代表某一个常数。

matlab代码如下。基于1.1节的代码基础上,增加了透视变换环节实现。

%创建3维物体的二维投影(透视)
clear
clc
close all
for k=0:1:99

%创建3维立方体
Line_AB = Create_Cube(3);
Line_AB = Line_AB*2-1;
N=size(Line_AB,1);
Line_List_1 = Line_AB(:,1:3)';
Line_List_2 = Line_AB(:,4:6)';
% %旋转一定角度
    Line_List_1=Ro_Ma_3D(2,pi/100*k)*Ro_Ma_3D(1,pi/100*k)*Line_List_1;
    Line_List_2=Ro_Ma_3D(2,pi/100*k)*Ro_Ma_3D(1,pi/100*k)*Line_List_2;
%平移一定距离,防止正方体旋转时越过投影平面
Line_List_1=Line_List_1-[0;0;5]*ones(1,N);
Line_List_2=Line_List_2-[0;0;5]*ones(1,N);

To = [0,0,-1];
From = [0,0,0];
Up = [0,1,0];
%3D眼睛坐标
C = (To-From)/norm(To-From);
A = cross(C,Up)/norm(cross(C,Up));
B = cross(A,C);
ABC = [A',B',C'];
%xyz坐标下的点转换
Line_AB_ABC = zeros(size(Line_AB));
F_xyz = [0,0,0];%定义原点,透视视角有用
Line_ABC_1=(Line_List_1'-ones(N,1)*F_xyz)*ABC;
Line_ABC_2=(Line_List_2'-ones(N,1)*F_xyz)*ABC;
%透视
P_ABC_1=Line_ABC_1(:,1:2)./(Line_ABC_1(:,3)*ones(1,2));
P_ABC_2=Line_ABC_2(:,1:2)./(Line_ABC_2(:,3)*ones(1,2));

%投影到2D屏幕上
figure(1)
clf
hold on
for m=1:N
    P1=P_ABC_1(m,:);
    P2=P_ABC_2(m,:);
    plot([P1(1),P2(1)],[P1(2),P2(2)],'linewidth',1)
end
hold off
xlim([-0.8,0.8])
ylim([-0.8,0.8])
pause(0.5)

end


function Line_AB = Create_Cube(Dim)
%创建Dim维度的正方体,坐标范围0-1
%Dim = 3;
Line_AB = zeros(1,2*Dim);
Line_AB(Dim+1) = 1;
Line_AB_Old = Line_AB;
for k = 2:Dim
    %向另一个维度复制
    P_Old = size(Line_AB_Old,1);%上一个维度的线数
    Line_AB_New1 = [Line_AB_Old;Line_AB_Old];
    Line_AB_New1(P_Old+1:end,k) = 1;
    Line_AB_New1(P_Old+1:end,Dim+k) = 1;
    %连接相邻维度的线
    P_Old2 = 2^(k-1);%上一个维度的点数
    Vertex2 = Full_Choose([0;1],k-1);
    Line_AB_New2 = zeros(P_Old2,2*Dim);
    Line_AB_New2(:,1:k-1) = Vertex2;
    Line_AB_New2(:,Dim+1:Dim+k-1) = Vertex2;
    Line_AB_New2(:,Dim+k) = 1;
    %汇总
    Line_AB_Old = [Line_AB_New1;Line_AB_New2];
    
end
Line_AB = Line_AB_Old;
end

function FullList=Full_Choose(n_List,n)
%全排列,可以重复
%n_List元素
%n是全排列的位数
V_Str='Xgrid';
V_Str_Sum='';
X_List=1:numel(n_List);%设置索引列表
%思路是利用ndgrid方法,实现全排列。用eval函数执行
for k=1:n
    V_Str_Sum=[V_Str_Sum,V_Str,num2str(k),','];
end
V_Str_Sum(end)=' ';
Eval_Str=['[',V_Str_Sum,']=ndgrid(','X_List',');'];
eval(Eval_Str);
V_Str_Sum2=[];
for k=n:-1:1
    V_Str_Sum2=[V_Str_Sum2,V_Str,num2str(k),'(:),'];
end
V_Str_Sum2(end)=' ';
Eval_Str=['FullList_X=[',V_Str_Sum2,'];'];
eval(Eval_Str);

FullList=n_List(FullList_X);%把生成好的列表带入到nlist中
FullList=unique(FullList,'rows');
end

function Rotation_Matrix = Ro_Ma_3D(n,theta)
%创建3D的旋转矩阵
%n=1为x轴(yz平面),n=2为y轴(xz平面),n=3为z轴(xy平面)
switch n
    case 1
        Rotation_Matrix=[1,0,0;...
            0,cos(theta),-sin(theta);...
            0,sin(theta),cos(theta)];
    case 2
        Rotation_Matrix=[cos(theta),0,sin(theta);...
            0,1,0;...
            -sin(theta),0,cos(theta)];
    case 3
        Rotation_Matrix=[cos(theta),-sin(theta),0;...
            sin(theta),cos(theta),0;...
            0,0,1];
end
end

透视效果下方块旋转的效果。
在这里插入图片描述

2 四维空间在2维屏幕上的投影

2.1 四维空间与三维空间的一些区别

首先是四维空间的旋转。

广义上的旋转运动是平行于某一平面的运动,而不是沿着某一个轴进行运动。

二维空间中,具有2个坐标轴,可以组成1个平面。二维空间中的旋转,并不存在旋转轴。如果非要说有,那旋转轴也不是x轴y轴,而是不存在于二维空间中的z轴。

三维空间中,由于具有3个坐标轴,可以组成3个平面,所以在三维空间中,平行于面的旋转,总是可以找到一个轴与之对应。所以,三维空间是一个特例,旋转既可以用轴表示,也可以用面表示。

四维空间中,具有4个坐标轴,可以组成6个平面(3*4/2=6)。此时,平行于面进行旋转的描述是必要的。因为一个旋转面可以对应很多个垂直于面的轴。

旋转的数学描述是旋转矩阵。二维的旋转矩阵可以写作:
L X Y = [ cos ⁡ θ sin ⁡ θ − sin ⁡ θ cos ⁡ θ ] L_{XY}=\left[ \begin{matrix} \cos \theta& \sin \theta\\ -\sin \theta& \cos \theta\\ \end{matrix} \right] LXY=[cosθsinθsinθcosθ]

三维的旋转矩阵有3个,分别对应xy平面、yz平面、xz平面:
L X Y = [ cos ⁡ θ sin ⁡ θ 0 − sin ⁡ θ cos ⁡ θ 0 0 0 1 ] L_{XY}=\left[ \begin{matrix} \cos \theta& \sin \theta &0\\ -\sin \theta& \cos \theta &0\\ 0& 0&1\\ \end{matrix} \right] LXY=cosθsinθ0sinθcosθ0001
L X Z = [ cos ⁡ θ 0 − sin ⁡ θ 0 1 0 sin ⁡ θ 0 cos ⁡ θ ] L_{XZ}=\left[ \begin{matrix} \cos \theta& 0& -\sin \theta\\ 0& 1& 0\\ \sin \theta& 0& \cos \theta\\ \end{matrix} \right] LXZ=cosθ0sinθ010sinθ0cosθ
L Y Z = [ 1 0 0 0 cos ⁡ θ sin ⁡ θ 0 − sin ⁡ θ cos ⁡ θ ] L_{YZ}=\left[ \begin{matrix} 1& 0& 0\\ 0& \cos \theta& \sin \theta\\ 0& -\sin \theta& \cos \theta\\ \end{matrix} \right] LYZ=1000cosθsinθ0sinθcosθ

四维的旋转矩阵则有6个,这里就不一一列举了。旋转矩阵的构建规则,可以用下面的步骤去描述:

1 对于N维旋转矩阵,首先创建N维单位矩阵eye(N)
2 定义旋转平面。旋转平面为第i和第j维度所构成的平面(i<j)
3 第i行i列为cos(X),第j行j列为cos(X)
4 第i行j列为sin(X),第j行i列为sin(X)
5 当i+j为奇数,第j行i列更改为-sin(X);
  当i+j为偶数,第i行j列更改为-sin(X)。

第二个区别是4维空间中的差积描述。

三维空间中,差积可以描述为一个行列式。其中i、j、k为三维空间中x、y、z轴对应的三个单位向量。
U × V = ∣ i j k U 1 U 2 U 3 V 1 V 2 V 3 ∣ U\times V=\left| \begin{matrix} i& j& k\\ U_1& U_2& U_3\\ V_1& V_2& V_3\\ \end{matrix} \right| U×V=iU1V1jU2V2kU3V3
差积得到的结果为一个新的向量,同时垂直于U和V向量。

四维空间中,也可以依次类推,得到:
X 4 ( U , V , W ) = ∣ i j k w U 1 U 2 U 3 U 4 V 1 V 2 V 3 V 4 W 1 W 2 W 3 W 4 ∣ X_4(U,V,W)=\left| \begin{matrix} i& j& k& w\\ U_1& U_2& U_3& U_4\\ V_1& V_2& V_3& V_4\\ W_1& W_2& W_3& W_4\\ \end{matrix} \right| X4(U,V,W)=iU1V1W1jU2V2W2kU3V3W3wU4V4W4
其中X4代表四维空间中的差积,得到新向量同时垂直于UVW。

这些相关的计算在2.2节将会用到。

2.2 四维空间投影

四维空间投影到二维空间,需要先从4维空间投影到3维,之后再由3维空间投影到2维。

其中,三维空间投影到二维的方法,在第一章已经涉及到,这里没有任何区别。四维空间投影到三维的方法,可以参照三维投二维的方法进行类比。

1定义From、To、Up、Over点
2计算对应着ABCD坐标
3将实际坐标P(x,y,z,w)转换到眼睛坐标P'(x,y,x,w)
4计算4维空间的透视点P'(x,y,z),作为3维投影

其中,ABCD向量的计算方法类似于3维:
D = T o − F r o m ∥ T o − F r o m ∥ D=\frac{To-From}{\lVert To-From \rVert} D=ToFromToFrom
A = X 4 ( U p , O v e r , D ) ∥ X 4 ( U p , O v e r , D ) ∥ A=\frac{ X_{4}(Up,Over,D) }{\lVert X_{4}(Up,Over,D) \rVert} A=X4(Up,Over,D)X4(Up,Over,D)
B = X 4 ( O v e r , D , A ) ∥ X 4 ( O v e r , D , A ) ∥ B=\frac{ X_{4}(Over,D,A) }{\lVert X_{4}(Over,D,A) \rVert} B=X4(Over,D,A)X4(Over,D,A)
C = X 4 ( D , A , B ) C= X_{4}(D,A,B) C=X4(D,A,B)
我个人没有想象出Over点在什么位置,也不是太理解ABCD对应的四个向量。但是具体数学上的计算是没有问题的。

得到ABCD之后,坐标变换为:
P ′ = [ P x ′ P y ′ P z ′ P w ′ ] = [ ( P x − F x ) ( P y − F y ) ( P z − F z ) ( P w − F w ) ] ∗ [ A x B x C x D x A y B y C y D y A z B z C z D z A w B w C w D w ] P'=\left[ \begin{matrix} P'_x& P'_y& P'_z& P'_w\\ \end{matrix} \right] \\ =\left[ \begin{matrix} (P_x-F_x)& (P_y-F_y)& (P_z-F_z)& (P_w-F_w)\\ \end{matrix} \right] *\left[ \begin{matrix} A_x& B_x& C_x& D_x\\ A_y& B_y& C_y& D_y\\ A_z& B_z& C_z& D_z\\ A_w& B_w& C_w& D_w\\ \end{matrix} \right] P=[PxPyPzPw]=[(PxFx)(PyFy)(PzFz)(PwFw)]AxAyAzAwBxByBzBwCxCyCzCwDxDyDzDw
之后去掉P’w坐标,就代表着4维空间在3维空间上的投影。

对于4维空间在3维空间上的透视(完全想不懂这是个什么),也可以参考第一章中的公式:
x 透 视 = k x w , y 透 视 = k y w , z 透 视 = k z w x_{透视}=k\frac{x}{w} ,y_{透视}=k\frac{y}{w},z_{透视}=k\frac{z}{w} x=kwxy=kwyz=kwz
其中w是点P’w的坐标。k是某一缩放常数。

在把4维空间上的点投影到三维之后,就可以继续带入到上一章的内容,把三维空间上的点投影到二维空间。

matlab代码如下:

%创建4维物体的二维投影(透视)
clear
clc
close all

%创建4维立方体
Line_AB = Create_Cube(4);
Line_AB = Line_AB*2-1;
N=size(Line_AB,1);
for theta=0:5:180*3

%将直线分为AB两点的连线
Line_List_1 = Line_AB(:,1:4)';%A部分点坐标
Line_List_2 = Line_AB(:,5:8)';%B部分点坐标
%旋转一定角度
Line_List_1=Ro_Ma_4D(1,2,pi/180*theta)...
    *Ro_Ma_4D(3,4,pi/180*theta/2)...
    *Ro_Ma_4D(1,4,pi/180*theta/3)...
    *Line_List_1;
Line_List_2=Ro_Ma_4D(1,2,pi/180*theta)...
    *Ro_Ma_4D(3,4,pi/180*theta/2)...
    *Ro_Ma_4D(1,4,pi/180*theta/3)...
    *Line_List_2;

%平移一定距离
Line_List_1=Line_List_1-[0;0;2;4]*ones(1,N);
Line_List_2=Line_List_2-[0;0;2;4]*ones(1,N);
%观察视角4D
To_4 = [0,0,0,0];
From_4 = [1,0,0,0];
Up_4 = [0,1,0,0];
Over_4 = [0,0,1,0];
%定义ABCD矩阵
D=(To_4-From_4)/norm(To_4-From_4);
A=X4(Up_4,Over_4,D)/norm(X4(Up_4,Over_4,D));
B=X4(Over_4,D,A)/norm(X4(Over_4,D,A));
C=X4(D,A,B);
ABCD = [A',B',C',D'];
%将4D投影到3D坐标上
F_xyzw = [0,0,0,0];%定义原点,透视视角有用
Line_ABCD_1=(Line_List_1'-ones(N,1)*F_xyzw)*ABCD;
Line_ABCD_2=(Line_List_2'-ones(N,1)*F_xyzw)*ABCD;
%4D透视
P_ABCD_1=Line_ABCD_1(:,1:3)./(Line_ABCD_1(:,4)*ones(1,3));
P_ABCD_2=Line_ABCD_2(:,1:3)./(Line_ABCD_2(:,4)*ones(1,3));
%观察视角3D
To_3 = [0,0,0];
From_3 = [1,0,0];
Up_3 = [0,1,0];
%定义ABC矩阵3D眼睛坐标
C = (To_3-From_3)/norm(To_3-From_3);
A = cross(C,Up_3)/norm(cross(C,Up_3));
B = cross(A,C);
ABC = [A',B',C'];
%xyz坐标下的点转换
F_xyz = [0,0,0];%定义原点,透视视角有用
Line_ABC_1=(P_ABCD_1-ones(N,1)*F_xyz)*ABC;
Line_ABC_2=(P_ABCD_2-ones(N,1)*F_xyz)*ABC;
%透视
P_ABC_1=Line_ABC_1(:,1:2)./(Line_ABC_1(:,3)*ones(1,2));
P_ABC_2=Line_ABC_2(:,1:2)./(Line_ABC_2(:,3)*ones(1,2));

%投影到2D屏幕上
figure(1)
clf
hold on
for k=1:N
    P1=P_ABC_1(k,:);
    P2=P_ABC_2(k,:);
    plot([P1(1),P2(1)],[P1(2),P2(2)],'linewidth',1)
end
hold off
box on
xlim([-1.5,0.5])
ylim([-1,1])
pause(0.5)
end





function Line_AB = Create_Cube(Dim)
%创建Dim维度的正方体,坐标范围0-1
%Dim = 3;
Line_AB = zeros(1,2*Dim);
Line_AB(Dim+1) = 1;
Line_AB_Old = Line_AB;
for k = 2:Dim
    %向另一个维度复制
    P_Old = size(Line_AB_Old,1);%上一个维度的线数
    Line_AB_New1 = [Line_AB_Old;Line_AB_Old];
    Line_AB_New1(P_Old+1:end,k) = 1;
    Line_AB_New1(P_Old+1:end,Dim+k) = 1;
    %连接相邻维度的线
    P_Old2 = 2^(k-1);%上一个维度的点数
    Vertex2 = Full_Choose([0;1],k-1);
    Line_AB_New2 = zeros(P_Old2,2*Dim);
    Line_AB_New2(:,1:k-1) = Vertex2;
    Line_AB_New2(:,Dim+1:Dim+k-1) = Vertex2;
    Line_AB_New2(:,Dim+k) = 1;
    %汇总
    Line_AB_Old = [Line_AB_New1;Line_AB_New2];
    
end
Line_AB = Line_AB_Old;
end


function FullList=Full_Choose(n_List,n)
%全排列,可以重复
%n_List元素
%n是全排列的位数
V_Str='Xgrid';
V_Str_Sum='';
X_List=1:numel(n_List);%设置索引列表
%思路是利用ndgrid方法,实现全排列。用eval函数执行
for k=1:n
    V_Str_Sum=[V_Str_Sum,V_Str,num2str(k),','];
end
V_Str_Sum(end)=' ';
Eval_Str=['[',V_Str_Sum,']=ndgrid(','X_List',');'];
eval(Eval_Str);
V_Str_Sum2=[];
for k=n:-1:1
    V_Str_Sum2=[V_Str_Sum2,V_Str,num2str(k),'(:),'];
end
V_Str_Sum2(end)=' ';
Eval_Str=['FullList_X=[',V_Str_Sum2,'];'];
eval(Eval_Str);

FullList=n_List(FullList_X);%把生成好的列表带入到nlist中
FullList=unique(FullList,'rows');
end

function d=X4(a,b,c)
%输入a,b,c默认都是列向量,4行1列
%输出d是4维空间中的差积运算,默认也是列向量
%如果是行向量,输出也是行向量,但是中间过程也是转换为列向量

H=0;%是否为行向量
if size(a,1)==1
    a=a';
    H=1;
end
if size(b,1)==1
    b=b';
    H=1;
end
if size(c,1)==1
    c=c';
    H=1;
end

abc=[a,b,c]';
d1=abc(:,[2,3,4]);
d2=abc(:,[1,3,4]);
d3=abc(:,[1,2,4]);
d4=abc(:,[1,2,3]);

d=[det(d1);-det(d2);det(d3);-det(d4)];

if H==1
    d=d';
end
end

function Rotation_Matrix = Ro_Ma_4D(n1,n2,theta)
%4维,以平面作为基准进行选择
%比如n1=1,n2=2代表以xy平面为基准进行旋转
Dim1=min(n1,n2);
Dim2=max(n1,n2);

Rotation_Matrix=eye(4);
Rotation_Matrix(Dim1,Dim1)=cos(theta);
Rotation_Matrix(Dim1,Dim2)=-1*(-1)^(Dim1+Dim2)*sin(theta);
Rotation_Matrix(Dim2,Dim2)=cos(theta);
Rotation_Matrix(Dim2,Dim1)=(-1)^(Dim1+Dim2)*sin(theta);
end

具体的效果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42943114/article/details/108268914
今日推荐