1

Here is a povray code that I am trying to digest:

#include "colors.inc"

camera {
    location <4, 0, -10>
    look_at  <4, 0,  0>
} 


background{White}

light_source { <10, 10, 5> color White} 
light_source { <0, 20, 0> color White} 

//********************** Turtle Position ****************************      
// These represent the position and angle of the turtle
#declare cylinderWidth=.1;           
#declare locx = 0;
#declare locy = 0;
#declare myAngle = 0;   

//************************* Macros **********************************  
// This is a macro that moves the turtle forward by a distance s.
#macro kmove(s)    
   #declare locx_new = locx + s*cos(radians(myAngle));
   #declare locy_new = locy + s*sin(radians(myAngle));  
   cylinder { <locx, locy, 0>,    <locx_new, locy_new, 0>, s*cylinderWidth}
   #declare locx = locx_new;
   #declare locy = locy_new;   
#end


// This is a macro that is recursive for moving the turtle around. 
#macro koch(s, recursion_depth)
    #if (recursion_depth > 0)
        union {       
            object { koch(s/3,  recursion_depth-1)  }
            object {
                 #declare myAngle = myAngle + 60;
                 koch(s/3,  recursion_depth-1)   
                }    
            object {
                #declare myAngle = myAngle -120; 
                koch(s/3,  recursion_depth-1)    
            }
            object {   
                #declare myAngle = myAngle + 60;   
                koch(s/3,  recursion_depth-1)  
            } 

        }
    #else
        kmove(s);
    #end
#end  


//************************* Parameters  **********************************  
// This sets the number of levels of recursion
#declare myDepth = 0;                      

// This is the distance along x that the turtle moves. 
#declare mySize = 8; 

//*********************** DRAW THE TURTLE!!  ******************************* 
// This is the command for actually drawing the Turtle's path based in the
// distance and levels of recursion.
object{
  koch(mySize,myDepth) 
  pigment { color Blue }   
} 

What I do not understand is the macro 'koch' that involves the if statement. How does it make cylinders, as it does not involve the function kmove(s). It appears that every iteration makes three line segments, each of which have length s/3; and then it rotates them through some angle. But how does it do this, when it does not even involve kmove(s)?

Also, why aren't there any translate commands? Wouldn't every iteration produce line segments that overlap?

EDIT: Obviously, I ran the code before making this post, and it does in fact work. However, as it is obvious from what I have said above, I would like to understand how this code works.

Mack
  • 665
  • 2
  • 11
  • 20

1 Answers1

1

How does it make cylinders, as it does not involve the function kmove(s).

It does involve the macro kmove in the #else branch, which serves as recursion terminator here.

why aren't there any translate commands

The location of the cylinder is controlled directly during its creation:

cylinder { <locx, locy, 0>,    <locx_new, locy_new, 0>, s*cylinderWidth}

As the locx and locy variables are used (which are updated every time kmove is invoked!), the cylinders are placed at different positions.

To understand what happens here, try doing by hand what the POV-Ray parser does, i.e. replacing the macro invokations with the body of the same macro, inserting the values of the actual parameters where the formal parameters are referenced, deleting if-then-else cases whose conditions are not met etc.; eventually this should result in koch(mySize,myDepth) being reduced to a sequence of kmove bodies, i.e. a sequence of

#declare locx_new = locx + s*cos(radians(myAngle));
#declare locy_new = locy + s*sin(radians(myAngle));  
cylinder { <locx, locy, 0>,    <locx_new, locy_new, 0>, s*cylinderWidth}
#declare locx = locx_new;
#declare locy = locy_new;

with actual values instead of s formal parameter references. Note that by tracing the values of the loc and angle variables over this (non-recursive) sequence you can even get rid of their references with the sequence resulting in one of

cylinder { <locx, locy, 0>,    <locx_new, locy_new, 0>, s*cylinderWidth}

declarations (of course with references replaced by values again).