简体   繁体   中英

Constructing multiple paths inside a big cube in MATLAB

I have a big cube which is filled with many small cubes. I want to make 4 connected paths through the small cubes, each path with different color. We will end up with different color regions inside the cube. I have some codes from my previous questions ( Filing the entire volume of a cube with small cubes in MATLAB AND Program stucks in infinite loop although there is a condition to terminate it: MATLAB ). The code can build a path of any length <= number of small cubes, I've just added some adjustments to it and its working very well. What I want to do now, is just to repeat this 4 times, one time for every region. I added a for loop to do that, and I specified the number of cubes in every path. But it is not working! It seems that it only constructs the first path. Here is a fast explanation of how I build a path,

Start from any random cube, color it with some color (its region color), found its neighbors, choose any of its neighbors, and color that neighbor. Then for this currently selected neighbor, we repeat the same process, where we look to its neighbors and select any of them as the next move in the path. If the neighbors of a cube are all visited (belong to some path), the algorithm will select any not visited cube and move to it as long as it doesn't make the path disconnected. This is achieved by checking if the not visited cube to be selected has some visited neighbors, if it does, then we can move to it, because the path will be connected. The code that builds one region is working well, I just want to make this process four times, but that's not working. Here is the code,

%%
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
getNeighbourIndex = @(idx) iNeighbour(idx,~isnan(iNeighbour(idx,:))) ;
%set(hcube,'Visible','off')  %// turn off all small cubes
%CubeOfInterest = 32 ;      %// 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)
%% // Random path

rng(1)                     %// set that if you want reproducible results, otherwise comment it
set(hcube,'Visible','off')
startCubeIndex = randi([1 numel(hcube)],1) ;    %// random starting cube
%// startCubeIndex = 1 ;                            %// or fixed one

maxPathLength = 0 ;       %// maximum length of path
maxPathLength= maxPathLength+1; 
path_terminated = false ;   %// condition to get out of loop
path_visited = [] ;         %// store the generated path (visited cubes)this to be checked in case 2 as well. 

ptIndex = 1 ;
path_visited(1) = startCubeIndex ;
set(hcube( path_visited(ptIndex) ) ,'Visible','on','FaceColor','r','FaceAlpha',1)
availableAll =[1:125]; 

for i=1:4
    if (i==1)
        path_visited(1) = startCubeIndex ;
        maxPathLength=60; 
    elseif (i==2)
        ptIndex= ptIndex+1; 
        path_visited(ptIndex) = randi([1 max(availableAll)],1) ; 
        maxPathLength=30;
    elseif (i==3)
        ptIndex= ptIndex+1; 
        path_visited(ptIndex) = randi([1 max(availableAll)],1) ; 
        maxPathLength=20;
    elseif (i==4)
        ptIndex= ptIndex+1; 
        path_visited(ptIndex) = randi([1 max(availableAll)],1) ; 
        maxPathLength=15;
    end
    disp (maxPathLength)
while ~path_terminated
    available_next = getNeighbourIndex( path_visited(ptIndex) ) ;   %// get all the neighbours
    [~,~,ib] = intersect(path_visited,available_next) ;             %// check if we already went through some
    if ~isempty(ib)
        available_next(ib) = [] ;                                   %// remove visited cube from "available" list
    end
    nAvail = numel(available_next) ;                                %// number of actually available neighbour

    if nAvail == 0                                                  %// Exit loop if no neighbour available
        msgTerm = 'Path blocked. No other neighbour available.' ;   %// Reason for terminating path
        %//path_terminated = true ;
        %//here I want to make the modification. 
        looping=true; %//To keep looping until we find the correct next move. 
        counter=0; %//to iterate through the cubes which are not visisted.
        while looping==true
        counter= counter+1; 
        jump= availableAll (counter); %//select the first available cube and check if it is suitable or not  
            if (~isempty (intersect(getNeighbourIndex(jump), path_visited))) %// if the selcted cube has a visited neighbor, it means it is suitable. The path will stay connected.
                %good we found it. 
                 ptIndex = ptIndex+1 ; 
                 path_visited(ptIndex) = jump ; %//add the selected cube to the path. 
                 availableAll (availableAll==jump)= []; %//remove the selected cube from the list of available cubes. 
                 looping= false; %//stop looping. 
            end
        %continue
        end

    else 
        ptIndex = ptIndex+1 ;
        path_visited(ptIndex) = available_next( randi([1 nAvail],1) ) ;
        availableAll (availableAll==path_visited(ptIndex))= []; %//remove the selected cube from the list of available cubes. 
    end
    if ptIndex >= maxPathLength                                          %// exit loop if we reached the max number of elements
        msgTerm = 'Path terminated. Reached max number of elements.' ;   %// Reason for terminating path
        path_terminated = true ;
        continue;
    end

    %// choose one neighbour randomly among the available ones


    set(hcube( path_visited(ptIndex) ) ,'Visible','on','FaceColor','r','FaceAlpha',1)      %// highlight new cube
    set(hcube( path_visited(1:ptIndex-1) ) ,'Visible','on','FaceColor','g','FaceAlpha',.2) %// shade old cubes

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

Some parts of the code above are obtained from the questions I've linked. I've added the for loop, and the part which makes the move to a not visited cube in case neighbors are visited (code is under the comment "here I want to make the modification."). If you remove the for loop the code will work properly for 1 region. Notice that I didn't color the different regions yet, what matters now is how to repeat the same path building method for the 4 regions.

Can anyone please tell me what mistake I did, and how to fix it?

Thank You.

I figured it out. Here,

if ptIndex >= maxPathLength                                          %// exit loop if we reached the max number of elements
        msgTerm = 'Path terminated. Reached max number of elements.' ;   %// Reason for terminating path
        path_terminated = true ;
        continue;
    end

ptIndex will be greater than maxPathLength in the all 3 regions after constructing the first one. This is because ptIndex is incremented every time a cube is visited. Imagine we have visited 60 cubes in the first region, then ptIndex will be equal to 60. Now, the maxPathLength for the second region is 30. So, ptIndex > 30 which will cause the code to exit without building the second region. Hence, it's like we are only building the first region and stop after that. To fix that I compared the number of steps taken for every region with the maxPathLength of that region, like this,

if steps==maxPathLength                                  %// exit loop if we reached the max number of elements
     %   msgTerm = 'Path terminated. Reached max number of elements.' ;   %// Reason for terminating path
       path_terminated = true ;
       continue;
    end

where steps starts from 0 and grows to maxPathLength for every region (we initialize it to 0 before the second while and increment it with every iteration of the second while.)

The code is working well now.

Thank You.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM