////////////////////////////////////////////////////////////////////////// // Hexagonal Maze Macros // Copyright (c) 2000 by Robert Chaffe ////////////////////////////////////////////////////////////////////////// // First, some convenience macros. // Not sure if rand() ever returns a 1.0, which is just a wee bit too // high, so let's try this macro. #macro RandInt( MaxInt, Seed ) min( int( rand( Seed ) * MaxInt ), MaxInt - 1 ) #end #macro IsEven( Value ) ( mod( Value, 2 ) = 0 ? yes : no ) #end #macro IsOdd( Value ) ( mod( Value, 2 ) = 1 ? yes : no ) #end ////////////////////////////////////////////////////////////////////////// // Parameters for GenHexMaze macro: // pRows = number of rows in grid // pCols = number of columns in grid // Seed = float value for seed function // DoDebug = boolean indicating if debug messages should be written // FileName = name of file into which the direction data will be written #macro GenHexMaze ( pRows, pCols, Seed, DoDebug, FileName ) // A few safety checks. #if ( pRows < 4.0 ) #error "GenHexMaze: The Rows parameter should be 4 or greater." #end #if ( pCols < 4.0 ) #error "GenHexMaze: The Cols parameter should be 4 or greater." #end #if ( strlen( FileName ) < 1 ) #error "GenHexMaze: FileName length is zero?" #end #if ( strcmp( strlwr( FileName ), "amazehex.inc" ) = 0 ) #error "GenHexMaze: I will not overwrite myself!!" #end // Create the data file. We don't write to it for awhile, but it would // be a shame to do all the work and then have the open command fail. #fopen MazeDataFH FileName write // Just in case we were not given integers. #local Rows = int( pRows ); #local Cols = int( pCols ); // Initialize randomness. #local S = seed( Seed ); // Initialize array. #if ( DoDebug ) #debug concat("\nGenHexMaze: Initializing ",str(Rows,0,0),"x",str(Cols,0,0)," grid.\n") #end #local Grid = array[ Rows ][ Cols ] #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #local Grid[R][C] = 0; #local C = C + 1; #end #local R = R + 1; #end // Note the following direction values: // 1 = NorthWest // 2 = North // 4 = NorthEast // 8 = SouthEast // 16 = South // 32 = SouthWest // A grid cell with two or more direction values simply contains a sum of // the above values. For example, if a cell contains the value 10 then // there are two directions for leaving that cell - southeast and north. // Negative values are used while creating a "path." When each path has // been completed, the values in the cells for that path are made positive // (multiplied by -1). In this way, while we are tracing a new path we // know we are finished creating that path when we reach a cell with a // positive value. // Establish start and end cells and their initial direction values. #local StartEdge = RandInt( 2, S ); #switch ( StartEdge ) #case ( 0 ) // Start in north, or top row. End in south. #local StartRow = Rows - 1; #local StartCol = RandInt( Cols, S ); #if ( IsEven( StartCol ) ) #local Grid[ StartRow ][ StartCol ] = -1 * pow( 2, RandInt( 3, S ) ); #else #local Grid[ StartRow ][ StartCol ] = -2; #end #local ExitRow = 0; #local ExitCol = RandInt( Cols, S ); #if ( IsEven( ExitCol ) ) #local Grid[ ExitRow ][ ExitCol ] = 16; #else #local Grid[ ExitRow ][ ExitCol ] = 8 * pow( 2, RandInt( 3, S ) ); #end #break #else // Start in west, or left column. End in east. #local StartRow = RandInt( Rows, S ); #local StartCol = 0; #local Grid[ StartRow ][ StartCol ] = -31 * RandInt( 2, S ) - 1; #local ExitRow = RandInt( Rows, S ); #local ExitCol = Cols - 1; #local Grid[ ExitRow ][ ExitCol ] = ( RandInt( 2, S ) + 1 ) * 4; #end #local OnSolutionPath = yes ; // We're finished when the number of unused cells reaches zero. #local NumUnusedCells = ( Rows * Cols ) - 1; #while ( NumUnusedCells > 0 ) #if ( DoDebug ) #debug concat("\nGenHexMaze: Starting new path at ",str(StartRow,0,0),",",str(StartCol,0,0),".\n") #end #local CurrRow = StartRow; #local CurrCol = StartCol; #local NumUnusedCells = NumUnusedCells - 1; #local CreatingPath = yes ; #while ( CreatingPath ) #local Direction = RandInt( 6, S ); #local Attempt = 0; #local Success = 0; #while ( ( Attempt < 6 ) & ( Success = 0 ) ) #if ( DoDebug ) #debug concat("GenHexMaze: Attempting direction ",str(Direction,0,0),".\n") #end #switch ( Direction ) #case ( 0 ) // Northwest #if ( CurrCol > 0 & ( IsOdd( CurrCol ) | CurrRow < ( Rows-1 ) ) ) // Not at edge, so proceed. #local NextRow = ( IsOdd( CurrCol ) ? CurrRow : CurrRow + 1 ); #local NextCol = CurrCol - 1; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) // Next cell in selected direction not blocked, so proceed. #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 1; #if ( NextCellValue = 0 ) // Next cell unused, so set to direction value for current path. #local Grid[ NextRow ][ NextCol ] = -8; #else // Next cell on previous path, so add in the new direction value. #local Grid[ NextRow ][ NextCol ] = NextCellValue + 8; #end #end #end #break #case ( 1 ) // North #if ( CurrRow < ( Rows-1 ) ) #local NextRow = CurrRow + 1; #local NextCol = CurrCol; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 2; #if ( NextCellValue = 0 ) #local Grid[ NextRow ][ NextCol ] = -16; #else #local Grid[ NextRow ][ NextCol ] = NextCellValue + 16; #end #end #end #break #case ( 2 ) // Northeast #if ( CurrCol < ( Cols-1 ) & ( IsOdd( CurrCol ) | CurrRow < ( Rows-1 ) ) ) #local NextRow = ( IsOdd( CurrCol ) ? CurrRow : CurrRow + 1 ); #local NextCol = CurrCol + 1; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 4; #if ( NextCellValue = 0 ) #local Grid[ NextRow ][ NextCol ] = -32; #else #local Grid[ NextRow ][ NextCol ] = NextCellValue + 32; #end #end #end #break #case ( 3 ) // Southeast #if ( CurrCol < ( Cols-1 ) & ( IsEven( CurrCol ) | CurrRow > 0 ) ) #local NextRow = ( IsOdd( CurrCol ) ? CurrRow - 1 : CurrRow ); #local NextCol = CurrCol + 1; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 8; #if ( NextCellValue = 0 ) #local Grid[ NextRow ][ NextCol ] = -1; #else #local Grid[ NextRow ][ NextCol ] = NextCellValue + 1; #end #end #end #break #case ( 4 ) // South #if ( CurrRow > 0 ) #local NextRow = CurrRow - 1; #local NextCol = CurrCol; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 16; #if ( NextCellValue = 0 ) #local Grid[ NextRow ][ NextCol ] = -2; #else #local Grid[ NextRow ][ NextCol ] = NextCellValue + 2; #end #end #end #break #else // Southwest #if ( CurrCol > 0 & ( IsEven( CurrCol ) | CurrRow > 0 ) ) #local NextRow = ( IsOdd( CurrCol ) ? CurrRow - 1 : CurrRow ); #local NextCol = CurrCol - 1; #local NextCellValue = Grid[ NextRow ][ NextCol ]; #if ( NextCellValue >= 0 ) #local Success = 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] - 32; #if ( NextCellValue = 0 ) #local Grid[ NextRow ][ NextCol ] = -4; #else #local Grid[ NextRow ][ NextCol ] = NextCellValue + 4; #end #end #end #end // switch ( Direction ) #if ( Success = 0 ) // Attempted direction is blocked. #local Attempt = Attempt + 1; #local Direction = ( Direction = 5 ? 0 : Direction + 1 ); #else #if ( NextCellValue > 0 ) // Reached a cell of a previous path. #local CreatingPath = no ; #else #local NumUnusedCells = NumUnusedCells - 1; #end #end #end // ( ( Attempt < 6 ) & ( Success = 0 ) ) #if ( Success = 0 ) // All directions blocked. Mark current cell accordingly and back up. #if ( DoDebug ) #debug "GenHexMaze: All directions blocked. Backing up!\n" #end #local CurrCellValue = Grid[ CurrRow ][ CurrCol ]; #local Grid[ CurrRow ][ CurrCol ] = -99; #switch ( CurrCellValue ) #case ( -1 ) #if ( IsEven( CurrCol ) ) #local CurrRow = CurrRow + 1; #end #local CurrCol = CurrCol - 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 8; #break #case ( -2 ) #local CurrRow = CurrRow + 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 16; #break #case ( -4 ) #if ( IsEven( CurrCol ) ) #local CurrRow = CurrRow + 1; #end #local CurrCol = CurrCol + 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 32; #break #case ( -8 ) #if ( IsOdd( CurrCol ) ) #local CurrRow = CurrRow - 1; #end #local CurrCol = CurrCol + 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 1; #break #case ( -16 ) #local CurrRow = CurrRow - 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 2; #break #else #if ( IsOdd( CurrCol ) ) #local CurrRow = CurrRow - 1; #end #local CurrCol = CurrCol - 1; #local Grid[ CurrRow ][ CurrCol ] = Grid[ CurrRow ][ CurrCol ] + 4; #end // switch ( CurrCellValue ) #local NumUnusedCells = NumUnusedCells + 1; #else // Advance to the next cell selected for current path. #if ( DoDebug ) #debug concat("GenHexMaze: Advancing to ",str(NextRow,0,0),",",str(NextCol,0,0),".\n") #end #local CurrRow = NextRow; #local CurrCol = NextCol; #end #end // ( CreatingPath ) // Prepare for selection of next path's starting cell. #local NewStartCellNum = RandInt( NumUnusedCells, S ); #local N = 0; // Prepare array for solution path data. #if ( OnSolutionPath ) #local NumSolutionCells = ( Rows * Cols ) - NumUnusedCells; #local SolutionData = array[ NumSolutionCells ] #local SolutionData[ 0 ] = < ExitRow, ExitCol, Grid[ ExitRow ][ ExitCol ] >; #local P = 1; #end // Adjust cell values of current path. Also select next path's starting cell. #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #local CurrCellValue = Grid[R][C]; #if ( CurrCellValue < 0 ) #if ( CurrCellValue = -99 ) #local Grid[R][C] = 0; #else #local Grid[R][C] = -1 * CurrCellValue; #if ( OnSolutionPath ) #local SolutionData[P] = < R, C, Grid[R][C] >; #local P = P + 1; #end #end #end #if ( CurrCellValue = 0 | CurrCellValue = -99 ) #if ( N = NewStartCellNum ) #local StartRow = R; #local StartCol = C; #end #local N = N + 1; #end #local C = C + 1; #end #local R = R + 1; #end #local OnSolutionPath = no ; #if ( DoDebug ) #debug concat("GenHexMaze: Path complete. Number of unused cells = ",str(NumUnusedCells,0,0),".\n") #end #end // ( NumUnusedCells > 0 ) // Dump the data into a file for use by the other macros. #write ( MazeDataFH, "\"AMAZE_HEx\",", Rows, ",", Cols ) #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #write ( MazeDataFH, ",", Grid[R][C] ) #local C = C + 1; #end #local R = R + 1; #end #write ( MazeDataFH, ",\"SOLuTION\",", NumSolutionCells ) #local P = 0; #while ( P < NumSolutionCells ) #write ( MazeDataFH, ",", SolutionData[P] ) #local P = P + 1; #end #fclose MazeDataFH // End of macro GenHexMaze #end ////////////////////////////////////////////////////////////////////////// // Parameters for HasDirection macro: // CellValue = sum of all direction values in a given cell. // Direction = the direction value we are looking for. #macro HasDirection( CellValue, Direction ) #local Value = CellValue; #local HaveDirection = no ; #local I = 5; #while ( ( I >= 0 ) & ( HaveDirection = no ) ) #local DirTest = pow( 2, I ); #if ( Value >= DirTest ) #if ( Direction = DirTest ) #local HaveDirection = yes ; #end #local Value = Value - DirTest; #end #local I = I - 1; #end HaveDirection #end ////////////////////////////////////////////////////////////////////////// // Parameters for HexMaze macro: // FileName = name of file from which the direction data will be read // WallLength = length of a maze wall section // WallWidth = width of maze walls // WallHeight = height of maze walls #macro HexMaze( FileName, WallLength, WallWidth, WallHeight ) // A few safety checks. #if ( WallLength <= 0.0 ) #error "HexMaze: The WallLength parameter should be greater than zero." #end #if ( WallWidth <= 0.0 ) #error "HexMaze: The WallWidth parameter should be greater than zero." #end #if ( WallWidth > ( WallLength - 0.2 ) ) #error "Maze: The WallWidth parameter should be at least 0.2 less than the WallLength" #end #if ( WallHeight <= 0.0 ) #error "HexMaze: The WallHeight parameter should be greater than zero." #end #if ( strlen( FileName ) < 1 ) #error "HexMaze: FileName length is zero?" #end #if ( strcmp( strlwr( FileName ), "amazehex.inc" ) = 0 ) #error "HexMaze: I doubt that the maze data is in \"amazehex.inc\" !" #end #if ( file_exists( FileName ) = no ) #error "HexMaze: Did not find specified FileName." #end // Open the file and validate it. #fopen MazeDataFH FileName read #local FileTag = "x" #read ( MazeDataFH, FileTag ) #if ( strcmp( FileTag, "AMAZE_HEx" ) != 0 ) #fclose MazeDataFH #error "HexMaze: Expected name of file written by the GenHexMaze macro." #end // Extract the maze data. #local Rows = 0; #local Cols = 0; #read ( MazeDataFH, Rows, Cols ) #local Grid = array[ Rows ][ Cols ] #local CellValue = 0; #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #read ( MazeDataFH, CellValue ) #local Grid[R][C] = CellValue; #local C = C + 1; #end #local R = R + 1; #end // And the solution data. #read ( MazeDataFH, FileTag ) // Should be "SOLuTION". Just using inherent type checking. #local NumSolutionCells = 0; #read ( MazeDataFH, NumSolutionCells ) #local SolutionData = array[ NumSolutionCells ] #local SolutionVector = <0,0,0>; #local P = 0; #while ( P < NumSolutionCells ) #read ( MazeDataFH, SolutionVector ) #local SolutionData[P] = SolutionVector; #local P = P + 1; #end // File should close itself after last value is read. Error? #if ( defined( MazeDataFH ) ) #fclose MazeDataFH #end // Here is the wall shape. #local xNotch = (WallWidth/2) / tan(pi/3); #local Wall = prism { linear_sweep linear_spline 0, WallHeight, 7, <0, 0>, <-xNotch, WallWidth/2>, , , , <-xNotch, -WallWidth/2>, <0, 0> // translate <0,0,0.000001> } #local ZLength = sin( pi/3 ) * WallLength; // Now create the maze. union { #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #if ( IsEven( C ) ) #if ( HasDirection( Grid[R][C], 2 ) = no ) // North object { Wall translate <(WallLength*C*1.5)+(WallLength/2), 0, ((R+1)*2+1)*ZLength> } #end #if ( HasDirection( Grid[R][C], 4 ) = no ) // NorthEast object { Wall rotate <0,60,0> translate } #end #if ( HasDirection( Grid[R][C], 8 ) = no ) // SouthEast object { Wall rotate <0,-60,0> translate } #end #if ( ( R = 0 ) & ( HasDirection( Grid[R][C], 16 ) = no ) ) // South object { Wall translate <(WallLength*C*1.5)+(WallLength/2), 0, ZLength> } #end #if ( ( C = 0 ) & ( HasDirection( Grid[R][C], 32 ) = no ) ) // SouthWest object { Wall rotate <0,60,0> translate <0, 0, ((R+1)*2)*ZLength> } #end #if ( ( C = 0 | R = (Rows-1) ) & ( HasDirection( Grid[R][C], 1 ) = no ) ) // NorthWest object { Wall rotate <0,-60,0> translate } #end #else // C is odd. #if ( HasDirection( Grid[R][C], 2 ) = no ) // North object { Wall translate <(WallLength*(C-1)*1.5)+(WallLength*2), 0, ((R+1)*2)*ZLength> } #end #if ( HasDirection( Grid[R][C], 4 ) = no ) // NorthEast object { Wall rotate <0,60,0> translate } #end #if ( HasDirection( Grid[R][C], 8 ) = no ) // SouthEast object { Wall rotate <0,-60,0> translate } #end #if ( ( R = 0 ) & ( HasDirection( Grid[R][C], 16 ) = no ) ) // South object { Wall translate <(WallLength*(C-1)*1.5)+(WallLength*2), 0, 0> } #end #if ( ( R = 0 ) & ( HasDirection( Grid[R][C], 32 ) = no ) ) // SouthWest object { Wall rotate <0,60,0> translate } #end #end #local C = C + 1; #end #local R = R + 1; #end } // Here is a solution path object that the user may use as desired. #local Radius = ZLength - ( WallWidth/2 ) - 0.06; #declare HexMazeSolutionDots = union { #local P = 0; #while ( P < NumSolutionCells ) #local V = SolutionData[P]; sphere { <(V.y*1.5+1)*WallLength, max( Radius, WallHeight-Radius ), ( IsEven(V.y) ? (V.x+1)*2*ZLength : (V.x*2+1)*ZLength )>, Radius } #local P = P + 1; #end } // End of macro HexMaze. #end ////////////////////////////////////////////////////////////////////////// // Parameters for HexPipeMaze macro: // FileName = name of file from which the direction data will be read // PathWidth = width of path (actually, length of a hex side) // PipeWidth = width of pipe (the diameter!) // ExtendEnds = Boolean indicating if path ends should be extended #macro HexPipeMaze( FileName, PathWidth, PipeWidth, ExtendEnds ) // A few safety checks. #if ( PathWidth <= 0.0 ) #error "HexPipeMaze: The PathWidth parameter should be greater than zero." #end #if ( PipeWidth <= 0.0 ) #error "HexPipeMaze: The PipeWidth parameter should be greater than zero." #end #if ( PipeWidth > ( PathWidth - 0.1 ) ) #error "HexPipeMaze: The PipeWidth parameter should be at least 0.1 less than the PathWidth" #end #if ( strlen( FileName ) < 1 ) #error "HexPipeMaze: FileName length is zero?" #end #if ( strcmp( strlwr( FileName ), "amazehex.inc" ) = 0 ) #error "HexPipeMaze: I doubt that the maze data is in \"amazehex.inc\" !" #end #if ( file_exists( FileName ) = no ) #error "HexPipeMaze: Did not find specified FileName." #end // Open the file and validate it. #fopen MazeDataFH FileName read #local FileTag = "x" #read ( MazeDataFH, FileTag ) #if ( strcmp( FileTag, "AMAZE_HEx" ) != 0 ) #fclose MazeDataFH #error "HexPipeMaze: Expected name of file written by the GenHexMaze macro." #end // Extract the maze data. #local Rows = 0; #local Cols = 0; #read ( MazeDataFH, Rows, Cols ) #local Grid = array[ Rows ][ Cols ] #local CellValue = 0; #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #read ( MazeDataFH, CellValue ) #local Grid[R][C] = CellValue; #local C = C + 1; #end #local R = R + 1; #end // And the solution data. #read ( MazeDataFH, FileTag ) // Should be "SOLuTION". Just using inherent type checking. #local NumSolutionCells = 0; #read ( MazeDataFH, NumSolutionCells ) #local SolutionData = array[ NumSolutionCells ] #local SolutionVector = <0,0,0>; #local P = 0; #while ( P < NumSolutionCells ) #read ( MazeDataFH, SolutionVector ) #local SolutionData[P] = SolutionVector; #local P = P + 1; #end // File should close itself after last value is read. Error? #if ( defined( MazeDataFH ) ) #fclose MazeDataFH #end // Here is a pipe section. #local ZLength = sin( pi/3 ) * PathWidth; #local Pipe = cylinder { <0,0,0>, , PipeWidth/2 } // Now create the maze. union { #local R = 0; #while ( R < Rows ) #local C = 0; #while ( C < Cols ) #local XShift = (C*1.5+1)*PathWidth; #local ZShift = ( IsEven(C) ? (R+1)*2*ZLength : (R*2+1)*ZLength ); #local NorthWest = HasDirection( Grid[R][C], 1 ); #local North = HasDirection( Grid[R][C], 2 ); #local NorthEast = HasDirection( Grid[R][C], 4 ); #local SouthEast = HasDirection( Grid[R][C], 8 ); #local South = HasDirection( Grid[R][C], 16 ); #local SouthWest = HasDirection( Grid[R][C], 32 ); #local NeedSphere = yes ; #if ( NorthWest ) object { Pipe rotate <0,-150,0> translate } #if ( SouthEast | ( NorthEast & South ) ) #local NeedSphere = no ; #end #if ( ExtendEnds & ( C = 0 | ( IsEven(C) & R = (Rows-1) ) ) ) object { Pipe rotate <0,30,0> translate <((C-1)*1.5+1)*PathWidth, 0, ZShift+ZLength> } #if ( C > 0 ) object { Pipe rotate <0,-150,0> translate <((C-1)*1.5+1)*PathWidth, 0, ZShift+ZLength> } #end #end #end #if ( North ) object { Pipe rotate <0,-90,0> translate } #if ( South | ( SouthEast & SouthWest ) ) #local NeedSphere = no ; #end #if ( ExtendEnds & R = (Rows-1) ) object { Pipe rotate <0,90,0> translate } #if ( IsOdd(C) ) object { Pipe rotate <0,-90,0> translate } #end #end #end #if ( NorthEast ) object { Pipe rotate <0,-30,0> translate } #if ( SouthWest ) #local NeedSphere = no ; #end #if ( ExtendEnds & ( C = (Cols-1) | ( IsEven(C) & R = (Rows-1) ) ) ) object { Pipe rotate <0,150,0> translate <((C+1)*1.5+1)*PathWidth, 0, ZShift+ZLength> } #if ( C < (Cols-1) ) object { Pipe rotate <0,-30,0> translate <((C+1)*1.5+1)*PathWidth, 0, ZShift+ZLength> } #end #end #end #if ( SouthEast ) object { Pipe rotate <0,30,0> translate } #if ( ExtendEnds & ( C = (Cols-1) | ( IsOdd(C) & R = 0 ) ) ) object { Pipe rotate <0,-150,0> translate <((C+1)*1.5+1)*PathWidth, 0, ZShift-ZLength> } #if ( C < (Cols-1) ) object { Pipe rotate <0,30,0> translate <((C+1)*1.5+1)*PathWidth, 0, ZShift-ZLength> } #end #end #end #if ( South ) object { Pipe rotate <0,90,0> translate } #if ( ExtendEnds & R = 0 ) object { Pipe rotate <0,-90,0> translate } #if ( IsEven(C) ) object { Pipe rotate <0,90,0> translate } #end #end #end #if ( SouthWest ) object { Pipe rotate <0,150,0> translate } #if ( ExtendEnds & ( C = 0 | ( IsOdd(C) & R = 0 ) ) ) object { Pipe rotate <0,-30,0> translate <((C-1)*1.5+1)*PathWidth, 0, ZShift-ZLength> } #if ( C > 0 ) object { Pipe rotate <0,150,0> translate <((C-1)*1.5+1)*PathWidth, 0, ZShift-ZLength> } #end #end #end #if ( NeedSphere ) sphere { , PipeWidth/2 } #end #local C = C + 1; #end #local R = R + 1; #end // A slight shift. This will align this maze with a "regular" hexagonal maze that uses the same direction data! translate <0, PipeWidth/2, 0> } // End of macro HexPipeMaze. #end