3D-Turtle
Interpretation

C. Jacob
Dept. of Computer Science, Programming Languages
University of Erlangen-Nuremburg

September 1994

(copyright)

Global variables

experimentName = "NGrowth";
examplesDirectory = "../Examples";

Turtle control

goturtle3D[lsystems_,
           iterations_Integer:1,
           runName_String:"Turtles",
           examplesDir_String:"Examples",
           doDisplayOnScreen_:True,
           doShowInteractiveSelection_:False,
           generation_Integer:1] := 
Module[{},

  experimentName = runName;
  
  Print[" "];
  Print["LSystems: ...................................................."];
  Print[" "];
  Print[ ColumnForm[lsystems]];
  Print[" "];
  
  Map[StackTurtleParam3D[#, iterations, {30,30,30}, 0.2, {0,0,0}, {1,1,1}]&, lsystems]; 

  
  userInfo["Protocolling ..."];
  protocolTurtles[StringJoin[examplesDir,"/",experimentName,".proto"]];
  
  
  showTurtles[globalTurtlePlots,
    StringJoin[examplesDir,"/",experimentName],
    doDisplayOnScreen, 
    doShowInteractiveSelection,
    generation];
  
  
  lsystems

];

Turtle interpretation

Initialization

doInitialize :=
{
globalMaxRange = 0.0; (* the maximum range for turtle plots *)

globalTurtleLines = {};
globalTurtlePlots = {};
globalTurtleLSystems = {};
}

Options

Options[turtleInterpretation] :=
{
  Iterations -> 1,
  StartPosition -> {1.,1.,0.},
  StartDirection -> {0,0,1.},

  MaxNumberOfPaths -> 400,
  MaxPathLength -> 200,
  
  DefaultDrawColor -> 0.6,
  
  InterpretationTable ->
    {
      FO -> forward,
      BA -> back,
      
      YL -> yawLeft,
      YR -> yawRight,
      
      PD -> pitchDown,
      PU -> pitchUp,
      
      RL -> rollLeft,
      RR -> rollRight,
      
      N  -> north,
      E  -> east,
      S  -> south,
	     W  -> west,
	     
	     DP -> drawPoint,
	     DPLY -> drawPolygon,

      STACK[x___] :> {push,x,pop},
      SEQ[x___] :> {x},
      
      CO[c_] :> setColor[c]
      
     },
     
   GraphicOptions ->
   {
     AspectRatio -> 1,
	    Axes -> True,
	    Boxed -> True,
	        (**ViewPoint->{-2.644, -0.679, 2.000},**)
	    (**PlotRange -> {{-10,10},{-10,10},{0,15}},**)
	    PlotRange -> All,
       DisplayFunction -> $DisplayFunction
   }
	 
};

3D-Turtle interpretation

turtleInterpretation[turtleExpr_, opts___] :=
Module[
	{  
	   dim1 = MaxPathLength /. {opts} /. Options[turtleInterpretation],
    dim2 = MaxNumberOfPaths /. {opts} /. Options[turtleInterpretation],
    
    X = N[StartPosition /. {opts} /. Options[turtleInterpretation] ], 
    U = N[StartDirection /. {opts} /. Options[turtleInterpretation] ], 

    yawMatrix,
    pitchMatrix,
    rollMatrix,

	  interpretationTable = 
	    InterpretationTable /. {opts} /. Options[turtleInterpretation],

    turtleStack = {{startposn//N, startdir//N}},

    i = 1,
    count,
    
    currentColor = 
      DefaultDrawColor /. {opts} /. Options[turtleInterpretation]
  },
  
  count = {1};
  paths = {Table[Null,{dim2}]};
  paths[[1,1]] = X;

  
  (* --- Turtle INTERPRETATION ----------------------- *)
  
  Attributes[turtle] = Listable;

  (* --- without parameters -------------------------- *)
  
  (***
  turtle[north] := If[U[[1]]<0,U = U.yawleftmatrix[],
                     If[U[[1]]>0,U = U.yawrightmatrix[],U]];
  turtle[south] := If[U[[1]]>0,U = U.yawleftmatrix[],
                     If[U[[1]]<0,U = U.yawrightmatrix[],U]];
  turtle[east]  := If[U[[2]]>0,U = U.yawleftmatrix[],
                     If[U[[2]]<0,U = U.yawrightmatrix[],U]];
  turtle[west]  := If[U[[2]]<0,U = U.yawleftmatrix[],
                     If[U[[2]]>0,U = U.yawrightmatrix[],U]];
  ***)
  
  (* --- with parameters ----------------------------- *)
  
  turtle[forward[s_]] := paths[[i, ++count[[i]]]] 
                         = Graphics3D[{Thickness[0.02],
                                       Hue[currentColor],
                                       Line[{X,X += s U}]}];
  turtle[back[s_]]    := paths[[i, ++count[[i]]]] 
                         = Graphics3D[{Thickness[0.02],
                                       Hue[currentColor],
                                       Line[{X,X -= s U}]}];
  
  turtle[drawPoint[s_,c_]] := paths[[i, ++count[[i]]]] 
                         = Graphics3D[{PointSize[.01 s],
                                       Hue[c],
                                       Point[X]}];
  
  turtle[drawPolygon[s_,c_,polyCoords_]] := paths[[i, ++count[[i]]]]
                         = Graphics3D[{
                             Hue[c],
                             Polygon[Map[s (X+#)&, polyCoords]]
                           }];
                           
  turtle[GRAPHICS[g_,s_]] := paths[[i, ++count[[i]]]] 
                        = TranslateShape[AffineShape[g,{s,s,s}],X];

  turtle[yawLeft[a_]]   := U = U.yawMatrix[ a Degree] // N;
  turtle[yawRight[a_]]  := U = U.yawMatrix[-a Degree] // N;
 
  turtle[pitchDown[a_]] := U = U.pitchMatrix[ a Degree] // N;
  turtle[pitchUp[a_]]   := U = U.pitchMatrix[-a Degree] // N;
 
  turtle[rollLeft[a_]]  := U = U.rollMatrix[ a Degree] // N;
  turtle[rollRight[a_]] := U = U.rollMatrix[-a Degree] // N;
  
  turtle[turnAround[]]  := U = U.yawMatrix[180 Degree] // N;
  
  turtle[setColor[c_]]  := (currentColor = c);
                         
  (***
  turtle[growBloom[s_]] := paths[[i, ++count[[i]]]]
                         = Graphics3D[{PointSize[.05],
                                       Hue[First[s]],
                                       Point[X]}];
  turtle[growLeaf[s_]]  := paths[[i, ++count[[i]]]]
                         = Graphics3D[Point[X]];
  ***)
  
  (* --- Stacking ------------------------------------ *)
  
  turtle[push]    := PrependTo[turtleStack, {X,U}];

  turtle[pop]     := ({X,U} = First[turtleStack]; 
                      AppendTo[paths, Table[Null, {dim1}]]; 
                      AppendTo[count, 1];
                      paths[[++i, 1]] = X; 
                      turtleStack = Rest[turtleStack]);

				
  (* --- Rotation matrices --------------------------- *)
  
  yawMatrix[a_]   := {{ Cos[a], Sin[a], 0     },
                      {-Sin[a], Cos[a], 0     },
                      { 0     , 0     , 1     }};
                               
  pitchMatrix[a_] := {{ Cos[a], 0     ,-Sin[a]},
                      { 0     , 1     , 0     },
                      { Sin[a], 0     , Cos[a]}};
  
  rollMatrix[a_]  := {{ 1     , 0     , 0     },
                      { 0     , Cos[a],-Sin[a]},
                      { 0     , Sin[a], Cos[a]}};
  

  (* --- now start the interpretation actions ... --------- *)

  (**Print["Starting turtle interpretation ..."];**)
  (**Print["turtleExpr: ",turtleExpr];**)
  
  interpretationTime = 
    First[Timing[turtle[turtleExpr //. interpretationTable]]];
    
  (**Print["Time needed: ",interpretationTime];**)
  
  paths = 
    Map[Drop[#,1]&,
      Map[Take[paths[[#]], count[[#]]] &, Range[i]]
    ] // Flatten; 
		
  (**Print["Graphics expressions: ",paths];**)
		
  
  (* --- Fitness calculations --------------------- *)
  
  (* ... *)
  
  
  (* --- Prepare for graphics output -------------- *)
  
  
  turtlePlot = 
  Show[
    {paths,
     Graphics3D[Point[StartPosition /. {opts} /. Options[turtleInterpretation]]]
    },
		 GraphicOptions /. {opts} /. Options[turtleInterpretation]
  ];
  
  turtlePlot
  
]; (* end module *)

Utilities

Reset global turtle variables

resetTurtles := (globalTurtlePlots = {}; 
                 globalTurtleLines = {}; 
                 globalTurtleLSystems = {});

Protocol turtle interpretation

protocolTurtles[protoFile_String] :=
Module[{tmpOutputStream, tmpAxiom, tmpRules},

  tmpOutputStream = OpenWrite[protoFile];

  WriteString[tmpOutputStream, StringJoin["\n\nUserInput: ", ToString[userInputIndices],"\n"]];

  (* Reset user input *)
  userInput = .;

  Do[
    tmpAxiom = globalTurtleLSystems[[i,1]];
    tmpRules = globalTurtleLSystems[[i,2]];

    WriteString[tmpOutputStream, "\nAxiom: ", tmpAxiom];
    WriteString[tmpOutputStream, "\nRules: ", tmpRules];
    WriteString[tmpOutputStream, "\nFitness: ", populationFitnesses[[i]]],

    {i,1,Length[globalTurtleLSystems]}
  ];

  WriteString[tmpOutputStream, "\n\nPopulationHistory: ",populationHistory];

  Close[protoFile];

];

Show turtles

Needs["Statistics`DescriptiveStatistics`"];

showTurtles[turtlePlots_,
            mpsFile_String,
            doDisplayOnScreen_:False,
            doShowInteractiveSelection_:False,
            generation_Integer] := 

  Module[{width, turtlePlot, thePlotLabel},
  
    width = Floor[N[Sqrt[Length[turtlePlots]]]];
    If[width width < Length[turtlePlots], width++]; 

    plotsTable = Table[Show[Graphics[Line[{0.0}]], DisplayFunction -> Identity],
                       {width width}];
    (*
    Print["plots: ",Length[turtlePlots]];
    Print["width: ", width];
    Print["plotsTable: ",plotsTable];
    *)

    Do[
      plotsTable[[i]] = Show[turtlePlots[[i]],
                             PlotLabel -> StringJoin["-- ",ToString[i]," --\n",
                                            ToString[populationFitnesses[[i]]]," \n "],
                             PlotRange -> Table[{-globalMaxRange,globalMaxRange}, {3}], 
                             Axes -> True,
                             DisplayFunction -> Identity],

      {i,1,Length[turtlePlots]}
    ];

    (* Turtle plots *)
    (**
    If[doDisplayOnScreen === True,
      displayRule = DisplayFunction -> $DisplayFunction,
      displayRule = DisplayFunction -> Identity
    ];
    **)
    displayRule = DisplayFunction -> $DisplayFunction;

    
    thePlotLabel = StringJoin["Gen. ",ToString[generation]];
    If[doShowInteractiveSelection == True,
       thePlotLabel = 
         StringJoin[thePlotLabel,
                    "\nIA Sel: ",ToString[userInputIndices]]
    ];
       
    turtlePlot = 
    Show[GraphicsArray[Partition[plotsTable,width]], 
         PlotLabel -> thePlotLabel,
         displayRule];
    (**
    userInfo["Saving turtle graphic ..."];
    saveGraphic[StringJoin[mpsFile,".mps"], turtlePlot];
    **)

    (* Fitness curves *)

    AppendTo[minFitness,N[Min[populationFitnesses]]];
    AppendTo[maxFitness,N[Max[populationFitnesses]]];
    AppendTo[aveFitness,N[Mean[populationFitnesses]]];

    curve1 = ListPlot[minFitness, PlotJoined -> True, 
                      PlotStyle -> {Dashing[{.01}]}, DisplayFunction -> Identity];
    curve2 = ListPlot[maxFitness, PlotJoined -> True,
                      PlotStyle -> {{Thickness[0.02], GrayLevel[0.5]}},
                      DisplayFunction -> Identity];
    curve3 = ListPlot[aveFitness, PlotJoined -> True, DisplayFunction -> Identity];

    fitnessPlot = 
    Show[curve1,curve2,curve3,
      PlotLabel -> "Best, Mean and Worst Fitness",
      PlotRange -> All,
      DisplayFunction -> $DisplayFunction];

    userInfo["Saving fitness graphic ..."];
    saveGraphic[StringJoin[mpsFile,".fit.mps"], fitnessPlot];

    (* Fitness histogram *)

    histDataMaxLength = Max[Map[Length[#]&,populationFitnessesList]];
    histData = {};

    (**
    Map[
      If[(l = Length[#]) < histDataMaxLength, 
      AppendTo[#,Table[0,{histDataMaxLength-l}]]]&, populationFitnessesList
    ];
    **)
    
    (**
    histPlot = 
    Show[BarChart3D[
           populationFitnessesList,
         DisplayFunction -> Identity]];

    userInfo["Saving fitness histogram ..."];
    saveGraphic[StringJoin[mpsFile,"hist.mps"], histPlot];
    **)
  ];

Save graphics and compress with gzip

saveGraphic[fileName_String,plot_] :=

  Module[{},

  Display[fileName,plot];

  Run["gzip",fileName];

  ]; (* end module *)

Drawing a box

box[x_,y_,z_,w_,d_,h_] :=
  Graphics3D[
   {
    Line[ {{x,y,z},
           {x+w,y,z},
           {x+w,y+d,z},
           {x,y+d,z},
           {x,y,z} 
          }],
    Line[ {{x,y,z+h},
           {x+w,y,z+h},
           {x+w,y+d,z+h},
           {x,y+d,z+h},
           {x,y,z+h} 
          }],
    Line[ {{x,y,z}, {x,y,z+w}} ],
    Line[ {{x+w,y,z}, {x+w,y,z+h}} ],
    Line[ {{x+w,y+d,z}, {x+w,y+d,z+h}} ],
    Line[ {{x,y+d,z}, {x,y+d,z+h}} ]
   }
  ];

Show[box[-5,-5,-5,10,10,10],
     box[-10,-10,-10,20,20,20]]