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?
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.