在 MATLAB 中用小立方体填充立方体的整个体积 [英] Filing the entire volume of a cube with small cubes in MATLAB

查看:86
本文介绍了在 MATLAB 中用小立方体填充立方体的整个体积的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 MATLAB 中构建了一个空心立方体,我想用小立方体完全填充它的体积.然后我想找到一种方法来访问这些立方体并通过它们建立路径,即如果当前访问了立方体 x,则应该有一种方法可以知道它的右、左、上、下、前和后最近的邻居是什么(最近的邻居=当前立方体旁边的立方体).我想我们有 6 个邻居,因为我们有 6 个不同的立方体面.

通过了解每个方向最近的立方体,可以将穿过立方体的路径定义为一系列步骤(例如,右、左、左、上、右、前).我认为为了能够访问每个小立方体并移动到附近的立方体,我们需要在矩阵(可能是 3D)中表示小立方体,如果一个小立方体的右侧有一个相邻的立方体 x,那么在矩阵中,x将出现在小立方体当前列旁边的列中.此外,如果在另一个深度层有一个直接邻居(相同的 x、y 坐标但不同的 z 坐标,例如,前后邻居)应该被指出.有没有更简单的方法来识别邻居?

我通过 rayryeng 获得了一个代码(

谁能告诉我如何解决这个问题并构建 3D 矩阵(或任何其他更简单的方法来表示每个立方体的邻居)?

详细说明小立方体邻居问题.考虑在大立方体内部的任何地方放置一个立方体 C.让立方体位置为 (.5,.5,.5),我们可以将其视为立方体的中心.然后,这个立方体将有 6 个相邻立方体(直接放置在它旁边),每个轴有 2 个相邻立方体.所以,对于立方体 (.5,.5,.5),我们有,

C 右侧的 x 轴邻居 (.5 +offset, .5, .5)

C 左侧的 x 轴邻居 (.5 -offset, .5, .5)

y 轴与 C 的顶部相邻 (.5 , .5+offset, .5)

与 C 底部相邻的 y 轴 (.5 , .5-offset, .5)

z 轴与 C 后一个深度相邻 (.5 , .5, .5+offset)

z 轴与 C 前一个深度相邻 (.5 , .5, .5-offset)

其中偏移量可以被视为立方体中心与其任何面之间的距离.这只是澄清想法的解释,不需要以相同的方式实现.我希望这很清楚,如果您能帮助我构建这个邻域矩阵,我将不胜感激.

谢谢.

解决方案

同样的原理,我们先建一个大立方体,然后在角落里建一个小立方体,然后用小偏移量重复小立方体的建造,直到填满为止.与旧代码的主要区别在于,这次每个坐标集的阶跃变化是受控的(小立方体的x,y,z坐标的函数)而不是随机的.

%%clf;图1);格式紧凑h(1) = axes('位置',[0.2 0.2 0.6 0.6]);%这些是立方体的不同 8 个顶点,每个顶点由其 3 x y z 坐标定义:垂直 = [ 1 1 -1;-1 1 -1;-1 1 1;1 1 1;-1 -1 1;1 -1 1;1 -1 -1;-1 -1 -1];%这些是立方体的 6 个面,每个面都通过连接 4 个可用顶点来定义:fac = [1 2 3 4;4 3 5 6;6 7 8 5;1 2 8 7;6 7 1 4;2 3 5 8];%//我们想要多少个小立方体主立方体 = 2 ;%//主立方体侧面的尺寸nCubeOnSide = 5 ;%//主立方体的行/列"中小立方体的数量nCubesTotal = nCubeOnSide^3 ;%//小立方体的总数% 定义主容器立方体MainCube.Vertices = vert *(2/MainCubeSide) ;%//因为上面定义的立方体已经有一个边=2MainCube.Faces = fac ;MainCube.FaceColor = 'w' ;hMainCube = patch(MainCube);%//第一个大立方体的补丁函数.轴([-1, 1, -1, 1, -1, 1]);轴相等;坚持,稍等;材料金属;alpha('颜色');alphamap('减速');视图(138,24)%视图(3);%%//先生成每个立方体的所有坐标dstep = MainCubeSide/nCubeOnSide ;%//小立方体顶点的步长vElem = bsxfun(@plus, vert/nCubeOnSide , -( MainCubeSide/2 - dstep/2)*[1 1 1] ) ;%//基本立方体顶点%%坚持,稍等;coords = zeros( size(vElem,1),size(vElem,2), nCubesTotal);%//存储坐标颜色 = zeros( nCubesTotal , 3 ) ;%//存储颜色hcube = zeros( nCubesTotal , 1 ) ;%//存储补丁对象的句柄iNeighbour = zeros( nCubesTotal , 6 ) ;%//保存邻居的索引idc = permute( reshape(1:nCubesTotal,nCubeOnSide,nCubeOnSide,nCubeOnSide) , [3 2 1] ) ;%//对于每个立方体...iCube = 0 ;for iline=1:nCubeOnSide %//行对于 icol=1:nCubeOnSide %//列for ih=1:nCubeOnSide %//切片(高度)iCube = iCube + 1 ;%//取基角坐标,给每个坐标加上一个偏移量coords(:,:,iCube) = bsxfun(@plus, vElem, dstep*[(iline-1) (icol-1) (ih-1)]);%//保存颜色颜色(iCube,:) = rand(1,3);%//绘制立方体hcube(iCube) = patch('Faces', fac, 'Vertices', coords(:,:,iCube), 'FaceColor', color(iCube,:));drawow %//只是为了中间显示,你可以注释这两行pause(0.05) %//仅用于中间显示,您可以注释这两行%//保存相邻的立方体索引ixAdj = [iline-1 iline+1 icol-1 icol+1 ih-1 ih+1] ;%//相邻立方体的索引idxFalse = (ixAdj<1) |(ixAdj>nCubeOnSide) ;%//检测将超出"主立方体的立方体ixAdj(idxFalse) = 1 ;%//只是为了在此阶段不会出现索引"错误iNeighbour(iCube,:) = [idc(ixAdj(1),icol,ih) idc(ixAdj(2),icol,ih) ...idc(iline,ixAdj(3),ih) idc(iline,ixAdj(4),ih) ...idc(iline,icol,ixAdj(5)) idc(iline,icol,ixAdj(6)) ] ;iNeighbour(iCube,idxFalse) = NaN ;结尾结尾结尾

此代码将每个立方体的句柄保存在变量 hcube 中,因此您可以根据需要在所有立方体上批量分配属性.例如 delete(hcube) 会一次性删除所有的小立方体,或者 set(hcube,'Facealpha',0.5) 会使所有的立方体半透明.>

您还可以仅设置/更改其中一个子集的属性hcube(idx_subset) = ....这就是通过索引了解相邻立方体可能有用的地方,但您的相邻问题尚未完全定义.

<小时>

我在主循环中添加了邻居跟踪.这可能不是最有效的方法,但它确实保留了每个基本立方体的所有邻居的索引.iNeighbour 变量(大小:nCubesx6)保存每个邻居(6 个可能的邻居)的句柄索引.当邻居不存在时,我选择放置一个 NaN 代替.为了在没有 NaN 的情况下直接检索邻居的索引,我定义了一个辅助匿名函数:

getNeighbourIndex = @(idx) iNeighbour(idx,~isnan(iNeighbour(idx,:))) ;

现在可以帮助您跟踪给定立方体的所有邻居.例如:

set(hcube,'Visible','off') %//关闭所有小立方体CubeOfInterest = 111 ;%//选择一个立方体%//显示感兴趣的主要立方体,它的邻居是透明的set(hcube(CubeOfInterest),'Visible','on','FaceColor','r','FaceAlpha',1)set(hcube(getNeighbourIndex(CubeOfInterest)),'Visible','on','FaceColor','g','FaceAlpha',.05)

如您所见,无论我们是否靠近墙,所有邻居都在那里.

I have built a hollow cube in MATLAB, I want to completely fill its volume with small cubes. Then I want to find a way to access these cubes and make paths through them, i.e if cube x is currently accessed, there should be a way to know what is its right, left, top, bottom, front, and back closest neighbors (closest neighbors= the cubes directly beside the current cube). I think we have 6 neighbors, because we have 6 different faces of the cube.

By knowing the nearest cube at every direction, a path through the cubes can be defined as a series of steps (eg, right, left, left, top, right, front). I think to be able to access every small cube and move to near ones we need to represent the small cubes in a matrix (maybe 3D), where if a small cube has a neighbor cube x to its right, then in the matrix, x will appear in the column next to the current column of the small cube. Also, if there is a direct neighbor at another depth layer (same x, y coordinates but different z coordinate, eg, the front and back neighbors) it should be indicated. Is there an easier way to identify the neighbors?

I've obtained a code by rayryeng (Building a hollow cube and filing it with small cubes in MATLAB) to fill many small cubes randomly inside the big one and build a 3D matrix, where every slice of the matrix (depth) represents one of the small cubes and the rows and columns of every slice (8 rows and 3 columns) represent the x y z coordinates of the vertices of every small cube. Please take a look at the question link that I provided to see the code.

I want to make two modifications to the code,

1- fill the big cube with small cubes in an organized way not randomly.

2- adjust the 3D matrix to represent how the small cubes are neighbors to each other.

I've tried to adjust the code in the linked question to fill the cube in an organized way. This is my trial (I added the if else in the for loop),

   clf;
figure(1);
format compact 
h(1) = axes('Position',[0.2 0.2 0.6 0.6]);

%These are the different 8 vertices of the cube, each is defined by its 3 x
%y z coordinates:
vert = [1 1 -1; 
        -1 1 -1; 
        -1 1 1; 
        1 1 1; 
        -1 -1 1;
        1 -1 1; 
        1 -1 -1;
        -1 -1 -1];
%These are the 6 faces of the cube, each is defined by connecting 4 of the
%available vertices:
fac = [1 2 3 4; 
       4 3 5 6; 
       6 7 8 5; 
       1 2 8 7; 
       6 7 1 4; 
       2 3 5 8];

% I defined a new cube whose length is 1 and centers at the origin.
vert2 = vert * .05;  
fac2 = fac;


patch('Faces',fac,'Vertices',vert,'Facecolor', 'w');  % patch function for the first big cube. 
axis([-1, 1, -1, 1, -1, 1]);
axis equal;

hold on;

patch('Faces', fac2, 'Vertices', vert2, 'FaceColor', 'r', 'EdgeColor', 'none');
material metal;
alpha('color');
alphamap('rampdown');
%view(3);


hold on;
rng(123); %// Set seed for reproducibility
num_squares = 1000; %// Set total number of squares

%// New - to store the coordinates
coords = [];

%// For remembering the colours
colors = [];
%// For each square...

for idx = 1 : num_squares

    
    %// Take the base cube and add an offset to each coordinate
    %// Each coordinate will range from [-1,1]
    if (idx==1)
    vert_new = bsxfun(@plus, vert2, [.01 .01 .01]);
    
    else 
    vert_new = bsxfun (@plus, vert_new,[.01 .01 .01] );
    end
    %// New - For the coordinates matrix
    coords = cat(3, coords, vert_new);

    %// Generate a random colour for each cube
    color = rand(1,3);

    %// New - Save the colour
    colors = cat(1, colors, color);

    %// Draw the cube
    patch('Faces', fac, 'Vertices', vert_new, 'FaceColor', color,'EdgeColor', 'none');
end




%// Post processing
material metal;
alpha('color');
alphamap('rampdown');
view(3);

But I'm getting a result like the one in the following picture,

Can anyone please tell me how to solve this problem and build the 3D matrix (or any other easier way to represent the neighbors of every cube )?

EDIT: To elaborate more on the small cube neighbor issue. Consider having a cube C anywhere inside the big cube. Let the cube position be (.5,.5,.5) which we may think of as the center of the cube. Then, this cube will have 6 neighbor cubes (positioned directly beside it) with 2 neighbors per axis. So, for the cube (.5,.5,.5) we have,

x axis neighbor to the right of C (.5 +offset, .5, .5)

x axis neighbor to the left of C (.5 -offset, .5, .5)

y axis neighbor to the top of C (.5 , .5+offset, .5)

y axis neighbor to the bottom of C (.5 , .5-offset, .5)

z axis neighbor one depth after C (.5 , .5, .5+offset)

z axis neighbor one depth before C (.5 , .5, .5-offset)

where offset may be seen as the distance between the center of a cube and any of its faces. This is just an explanation to clarify the idea, it doesn't need to be implemented the same way. I hope this is clear, I would appreciate any help in constructing this neighborhood matrix.

Thanks.

解决方案

Same principle, we build a big cube, then a small one in the corner, then we repeat the small cube building with a small offset until we are full. The main difference with the old code is that this time the step change of each coordinate set is controlled (function of x,y,z coordinates of the small cube) instead of being random.

%%
clf; figure(1); format compact 
h(1) = axes('Position',[0.2 0.2 0.6 0.6]);

%These are the different 8 vertices of the cube, each is defined by its 3 x y z coordinates:
vert = [ 1  1 -1; -1  1 -1; -1  1  1; 1  1  1; -1 -1  1; 1 -1  1; 1 -1 -1; -1 -1 -1];

%These are the 6 faces of the cube, each is defined by connecting 4 of the available vertices:
fac = [1 2 3 4; 4 3 5 6; 6 7 8 5; 1 2 8 7; 6 7 1 4; 2 3 5 8];

%// How many small cube do we want
MainCubeSide = 2 ;              %// dimension of the side of the main cube
nCubeOnSide = 5 ;               %// number of small cube in one "row/column" of the main cube
nCubesTotal = nCubeOnSide^3  ;  %// total number of small cube

% define the Main container cube
MainCube.Vertices = vert *(2/MainCubeSide) ; %// because the cube as defined above has already a side=2
MainCube.Faces = fac ;
MainCube.FaceColor = 'w' ;

hMainCube = patch(MainCube);  %// patch function for the first big cube. 
axis([-1, 1, -1, 1, -1, 1]);
axis equal;
hold on;
material metal;
alpha('color');
alphamap('rampdown');
view(138,24)
%view(3);


%% // generate all the coordinates of each cube first
dstep = MainCubeSide / nCubeOnSide ;                                                 %// step size for small cube vertices
vElem = bsxfun(@plus, vert / nCubeOnSide , -( MainCubeSide/2 - dstep/2)*[1 1 1] )  ; %// elementary cube vertices

%%
hold on;
coords = zeros( size(vElem,1),size(vElem,2), nCubesTotal ) ;  %// To store the coordinates
colors = zeros( nCubesTotal , 3 ) ;                           %// To store the colours
hcube  = zeros( nCubesTotal , 1 ) ;                           %// To store the handles of the patch objects

iNeighbour = zeros( nCubesTotal , 6 ) ;   %// To save the index of the neighbours
idc = permute( reshape(1:nCubesTotal,nCubeOnSide,nCubeOnSide,nCubeOnSide) , [3 2 1] ) ;

%// For each cube ...
iCube = 0 ;
for iline=1:nCubeOnSide         %// Lines
    for icol=1:nCubeOnSide      %// Columns
        for ih=1:nCubeOnSide    %// Slice (height)
            iCube = iCube + 1 ;

            %// Take the base corner coordinates and add an offset to each coordinate
            coords(:,:,iCube) = bsxfun(@plus, vElem , dstep*[(iline-1) (icol-1) (ih-1)]);

            %// Save the colour
            colors(iCube,:) = rand(1,3) ; 

            %// Draw the cube
            hcube(iCube) = patch('Faces', fac, 'Vertices', coords(:,:,iCube), 'FaceColor', colors(iCube,:) ) ;

            drawnow     %// just for intermediate display, you can comment these 2 lines
            pause(0.05) %// just for intermediate display, you can comment these 2 lines

            %// save adjacent cubes indices
            ixAdj = [iline-1 iline+1 icol-1 icol+1 ih-1 ih+1] ;  %// indices of adjacent cubes
            idxFalse = (ixAdj<1) | (ixAdj>nCubeOnSide) ;  %// detect cube which would be "out" of the main cube
            ixAdj(idxFalse) = 1 ;                                %// just to not get an "indexing" error at this stage
            iNeighbour(iCube,:) = [idc(ixAdj(1),icol,ih)    idc(ixAdj(2),icol,ih) ...
                                   idc(iline,ixAdj(3),ih)   idc(iline,ixAdj(4),ih) ...
                                   idc(iline,icol,ixAdj(5)) idc(iline,icol,ixAdj(6)) ] ;
            iNeighbour(iCube,idxFalse) = NaN ;
        end
    end
end

This code saves the handle of each cube in the variable hcube so you can do assignment of property in bulk on all the cubes if you want. For example delete(hcube) will delete all the small cubes in one go, or set(hcube,'Facealpha',0.5) will make all cubes half transparent.

You can also set/change properties on only a subset of them hcube(idx_subset) = .... This is where knowing the adjacent cubes by their index could be useful, but your adjacency question is not completely defined yet.


Edit: I have added the neighbour tracking in the main loop. It is probably not the most efficient way to do it but it does keep an index of all the neighbour fro each elementary cube. The iNeighbour variable (size: nCubesx6) hold the handle index of each neighbour (6 possible neighbours). When a neighbour didn't exist, I opted to place a NaN instead. To retrieve the index of the neighbour directly without the NaNs, I defined a helper anonymous function:

getNeighbourIndex = @(idx) iNeighbour(idx,~isnan(iNeighbour(idx,:))) ;

Which now help you track all the neighbour of a given cube. For example:

set(hcube,'Visible','off')  %// turn off all small cubes
CubeOfInterest = 111 ;      %// select one cube
%// display the main cube of interest, and it's neighbours in transparency
set(hcube(CubeOfInterest),'Visible','on','FaceColor','r','FaceAlpha',1) 
set(hcube(getNeighbourIndex(CubeOfInterest)),'Visible','on','FaceColor','g','FaceAlpha',.05)

As you can see, all the neighbours are there, whether we are close to a wall or not.

这篇关于在 MATLAB 中用小立方体填充立方体的整个体积的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆