代码之家  ›  专栏  ›  技术社区  ›  Dania

在MATLAB中用小立方体填充立方体的整个体积

  •  4
  • Dania  · 技术社区  · 9 年前

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

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

    我获得了一个代码 rayryeng公司 ( Building a hollow cube and filing it with small cubes in MATLAB )在大立方体内随机填充许多小立方体,并构建一个3D矩阵,其中矩阵的每个切片(深度)表示一个小立方体,每个切片的行和列(8行和3列)表示每个小立方体顶点的x y z坐标。请查看我提供的问题链接以查看代码。

    我想对代码进行两次修改,

    1-以有组织的方式用小立方体填充大立方体,而不是随机。

    2-调整3D矩阵,以表示小立方体如何彼此相邻。

    我试图调整链接问题中的代码,以有组织的方式填充立方体。这是我的试验(我在for循环中添加了if else),

       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);
    

    但我得到了下图中的结果,

    enter image description here

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

    编辑:详细说明小立方体邻居问题。考虑在大立方体内的任何地方都有一个立方体C。让立方体的位置为(.5,.5,.5),我们可以将其视为立方体的中心。然后,此立方体将有6个相邻立方体(位于其旁边),每个轴有2个相邻立方体。因此,对于立方体(.5,.5,.5),

    x轴邻近C右侧(.5+偏移,.5,.5)

    与C左侧相邻的x轴(.5-偏移,.5,.5)

    y轴与C顶部相邻(.5,.5+偏移,.5)

    y轴与C底部相邻(.5,.5偏移,.5)

    z轴在C(.5,.5,.5+偏移)之后的一个深度附近

    z轴邻近C之前的一个深度(.5,.5,.5偏移)

    其中偏移可以被视为立方体的中心与其任何面之间的距离。这只是一个解释,以澄清这个想法,不需要以同样的方式实现。我希望这是明确的,我将感谢任何帮助来构建这个邻域矩阵。

    谢谢

    1 回复  |  直到 4 年前
        1
  •  7
  •   Hoki    9 年前

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

    buildcube

    %%
    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
    

    此代码将每个多维数据集的句柄保存在变量中 hcube 因此,如果需要,可以对所有立方体进行批量属性赋值。例如 delete(hcube) 将一次性删除所有小立方体,或 set(hcube,'Facealpha',0.5) 将使所有立方体半透明。

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


    编辑: 我已经在主循环中添加了邻居跟踪。这可能不是最有效的方法,但它确实保留了每个基本立方体的所有邻居的索引。 这个 iNeighbour 变量(大小: nCubesx6 )保持每个邻居(6个可能的邻居)的句柄索引。当邻居不存在时,我选择放置一个 NaN 相反 不使用 NaN公司 s、 我定义了一个助手匿名函数:

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

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

    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)
    

    cubes

    正如你所看到的,所有的邻居都在那里,无论我们是否靠近墙。