Example: Random Solar System

Create a ‘random’ solar system and surrounding star field using these commented Logo procedures:

TO solsys
  reset
  ;reset the turtles and clear the environment
  
  fullscreen
  ;don't display text
  
  ask "snappy [pullout 1000]
  ;ask the camera turtle to pull away from
  ;myrtle 1000 turtle units
  
  penup
  ;raise the turtle's pen so she doesn't draw
  
  hideturtle
  ;go incognito
  
  stars
  ;jump to the stars procedure, which creates
  ;a starfield around our solar system
  
  setfillcolor yellow
  icosphere 75
  ;make the sun, an icosphere 75 turtle units
  ;in radius
  
  dropanchor
  ;set Myrtle's 'anchor point' or the point
  ;she orbits around to her home position.
  ;By default it is somewhat in front of it.
  
  pullout 100
  ;pull out from the anchor point 100 turtle units
  
  repeat 10 [
    ;do the following ten times, to create ten planets
    
    pullout 100
    ;pull out from the anchor point 100 more
    ;turtle units
    
    orbitleft random 360
    ;orbit to the left between 0 and 360 degrees
    ;(up to one full orbit of the anchor point)
    
    planet repcount
    ;jump to the planet procedure, passing it
    ;the current iteration of the repeat loop
    ;as its parameter - the current planet number
    
  ]
  ;this is the end of the planet creation loop
  
  snappy:forever [orbitdown 0.001]
  ;orbit around the scene
  ;snappy: is shorthand for 'ask "snappy []'
  
END

TO stars
  ;create a starfield
  
  repeat 500 [
    
    randomvectors
    ;points the turtle in a random 3D
    ;direction. 'Vectors' describe absolute
    ;directions in 3D space using numbers.
    ;We call them vectors so as to not confuse
    ;them with relative directions such as up,
    ;down, left or right. A turtle with certain
    ;vectors will always point a certain way.
    ;For now, that's all you need to know!
    
    forward 1500 + random 500
    ;move forward 1500 turtle units plus
    ;between 0 and 499 turtle units in the
    ;turtle's forward direction - its forward
    ;'vector'
    
    ;Note: 'random' generates a number between
    ;0 and one less than the number you give it.
    ;The turtle knows what you mean when you say
    ;'random' because random is a primitive - a
    ;word the turtle knows.
    
    up 90
    ;tilt the turtle up 90 degrees, one quarter of
    ;a circle or one quarter of a complete rotation.
    ;Like as if you leaned back so far you were
    ;staring up at the sky
    
    randomfillcolor
    ;random means 'pick one at random', in this
    ;case a random fill color, numbered between 1
    ;and 15 (there are 16 default colors, but 0 is
    ;transparent and not typically a useful fill
    ;color!)
    
    spot 5 + random 5
    ;make a 'star', a spot with a radius of 5
    ;turtle units plus 0 - 4 additional turtle units
    
    home
    ;go back to the home position
  ]
  ;make 500 stars
  
END

TO planet :number
  ;make a planet. The number passed to
  ;planet is used to uniquely identify
  ;its 'model' - what it looks like
  
  newmodel :number [
    randomfillcolor
    ;Remember: not black!
    
    icosphere 10 + random 25
    ;create a randomly-sized sphere
    
    randomvectors
    ;'what's your vectors, Victor?'
    
    dountil fillcolor != yellow [randomfillcolor]
    ;not yellow!
    
    spot 10 + random 30
    ;create a randomly-sizes spot.
    ;If it's bigger than the sphere
    ;then it will act as a ring
    
  ]
  ;make a random planet model with the
  ;name of the planet number stored
  ;in the :number container, which was
  ;created when the number was passed
  ;in to the planet procedure
  
  ;Models are not unique to turtles, and
  ;so they each need a unique name, regardless
  ;of whatever turtle 'wears' them. But that
  ;name can just be a number, as long as it
  ;is a unique number
  
  hatch [
    ;hatch a new turtle from this spot
    
    showturtle
    ;show the hatchling's model. Hatchlings
    ;models are hidden when they are hatched
    ;as are those of other turtles when they
    ;are newly created. Only Myrtle is shown
    ;by default
    
    put 1 + random 10 in "speed
    ;generate a random number between
    ;0 and 9, add it to 1 and put it in
    ;a container named 'speed'
    
    setmodel :number
    ;set the hatchling's 'model' or
    ;appearance to the name stored in
    ;the :number container
    
    setanchor [0 0 0]
    ;set the 'anchor' or the point a turtle
    ;orbits around to [0 0 0], the location
    ;of the sun
    
    forever [
      orbitleft :speed * 0.001
    ]
    ;orbit around the sun 'forever'
  ]
  ;this is the end of the hatchling's code
  
END

Example: 3D Filled Trees

Filled triangles

TO tree
  clearscreen penup 
  setpos [0 80] setfillcolor 4 
  repeat 6 [
    setfillshade -6 + 3 * repcount 
    ;repcount returns the current iteration
    back 4 * repcount 
    fiso 8 * repcount 5 * repcount 
    ;fiso = filled iso triangle
    lower 0.1
  ] 
  setfillcolor 8 setfillshade 5 
  back 50 slideleft 10 
  quad 20 50
  ;trunk
END

‘Tents’ – fiso prisms

TO tree3d
  cs pu setpos [0 80] 
  ;cs = clearscreen
  ;pu = penup
  setfc 4 
  ;setfc = setfillcolor
  repeat 6 [
    setfs -6 + 3 * repcount 
    ;setfs = setfillshade
    bk 4 * repcount 
    ;bk = back  
    tent 8 * repcount 5 * repcount 10 
    lo 0.1
    ;lo = lower
  ] 
  setfc 8 setfs 5
  bk 50 sl 10 
  ;sl = slideleft
  voxeloid 20 50 10
  ;voxeloids are stretched cubes
END

Cones

TO conetree
  cs pu setpos [0 80] 
  setfc 4 up 90 
  repeat 6 [
    setfs -6 + 3 * repcount 
    ra 4 * repcount 
    cone 8 * repcount 5 * repcount 20
  ] 
  setfc 8 setfs 5 ra 50
  cylinder 8 50 20
END

Pyramids (5-sided ‘cones’)

TO pyramidtree
  cs pu setpos [0 80] 
  setfc 4 up 90 
  repeat 6 [
    setfs -6 + 3 * repcount ra 4 * repcount
    cone 8 * repcount 5 * repcount 4
    ;while there is also a pyramid primitive, you can 
    ;also create a pyramid by creating a 4-sided cone
  ] 
  setfc 8 setfs 5 ra 50 
  cylinder 8 50 4
END

4-sided cones

TO tetratree
  cs pu setpos [0 80] setfc 4 up 90 
  repeat 6 [setfs -6 + 3 * repcount 
    ra 4 * repcount 
    cone 8 * repcount 5 * repcount 3] 
  setfc 8 setfs 5 ra 50 
  cylinder 8 50 3
END

Example: Sierpinski’s Turtles

Sierpinski’s Gasket

These routines use recursion (they repeatedly call themselves) to realise different Sierpinski algorithms. Logo’s recursion capabilities and relational turtle make it excellent for the task of rendering these algorithms! They’re also very pretty.

TO half_s :size :level
  if :level = 0 [fd :size stop]
  half_s :size :level - 1
  lt 45 fd :size * sqrt 2 lt 45
  half_s :size :level - 1
  rt 90 fd :size rt 90
  half_s :size :level - 1
  lt 45 fd :size * sqrt 2 lt 45
  half_s :size :level - 1
END

TO sierpinski :size :level
  repeat 2 [
    half_s :size :level
    rt 90 fd :size rt 90
  ]
END

TO sierp
  cs pu back 180 pd sierpinski 3 5
END

sierp

Instead of drawing lines, we can construct triangles out of ‘pins’ dropped at appropriate points:

TO half_s :size :level
  penup
  if :level = 0 [fd :size stop]

  pin
  ;pin marks a point for use with pinfrag

  half_s :size :level - 1
  lt 45 fd :size * sqrt 2 lt 45
  half_s :size :level - 1
  rt 90 fd :size rt 90
  half_s :size :level - 1
  lt 45 fd :size * sqrt 2 lt 45
  half_s :size :level - 1

  pinfrag
  ;creates a triangle out of the last three 'pins'

END

sierp

We could drop twice as many pins and then select a color for each ‘frag’ (fragment) triangle from a list:

TO half_s :size :level
pu
if :level = 0 [fd :size stop]

pin
;drop pin

half_s :size :level - 1
lt 45 fd :size * sqrt 2 lt 45
half_s :size :level - 1

pin 
;drop another pin

rt 90 fd :size rt 90
half_s :size :level - 1
lt 45 fd :size * sqrt 2 lt 45
half_s :size :level - 1

setfc item :level [9 8 1 13] pinfrag
;pick a color from a list based on the current level and create the fragment

END

sierp

Sierpinski’s Triangle

It’s triangles all the way down!

TO sierpinski :size :level
  if :level > 0 [
    rt 30
    repeat 3 [
      fd :size
      rt 120
    ]
    left 30
    sierpinski :size / 2 :level - 1
    rt 30
    fd :size / 2
    left 30
    sierpinski :size / 2 :level - 1
    rt 30
    back :size / 2
    left 30
    rt 90
    fd :size / 2
    left 90
    sierpinski :size / 2 :level - 1
    left 90
    fd :size / 2
    rt 90
  ]
END

TO sierpinskiexample
  sierpinski 500 8
END

sierpinskiexample

Neat but a bit plain. We could use frag to create filled triangles, but we need to avoid z-fighting by adding a little bit of code to change the elevation of each ‘level’:

TO sierpinski :size :level
  if :level > 0 [

    pu setz 0 lower 0.1 * :level
    ;add above line to avoid z-fighting

    rt 30
    repeat [
      fd :size
      rt 120
    ]

    setfc :level
    ;set the fill color to the current 'level'
    frag
    ;create a filled triangle from the last three points (triangle)

    left 30
    sierpinski :size / 2 :level - 1
    rt 30
    fd :size / 2
    left 30
    sierpinski :size / 2 :level - 1
    rt 30
    back :size / 2
    left 30
    rt 90
    fd :size / 2
    left 90
    sierpinski :size / 2 :level - 1
    left 90
    fd :size / 2
    rt 90
  ]
END

sierpinskiexample

If you seperate the layers more, and use shard instead of frag

Sierpinski’s Tree

Trees are also a lot of fun, with the potential for so many variations!

TO tree :s :a :frac :depth
  fd :s / 2
  if :s >= 1 [
    local "p
    local "h
    make "p pos
    make "h heading
    left :a
    tree :s * 2 / 3 :frac * :a :frac :depth + 1
    pu setpos :p pd
    seth :h + :a
    tree :s * 2 / 3 :frac * :a :frac :depth + 1
  ]
END

TO drawtree
  reset
  cs pu bk 250 pd 
  tree 350 25 1.1 4
END

Note that this takes quite some time to render!

tree 350 60 1.1 4

TO tree :s :a :frac :depth
  fd :s / 2   
  if :s >= 1 [
     setpc :s
     ;set the pen color to the current 'size'
     ;which is fractional number truncated to an integer for use by setpc
     local "p
     local "h
     make "p pos
     make "h heading
     left :a     
     tree :s * 2 / 3 :frac * :a :frac :depth + 1
     pu setpos :p pd     
     seth :h + :a
     tree :s * 2 / 3 :frac * :a :frac :depth + 1
   ] 
END

tree 350 180 1.1 4

setpc 12 - :s

tree 350 280 1 4

Play with tree’s parameters and the colors and see what you can come up with! Logo is all about exploration, tweaking and tinkering. By seeing how altering the parameters can change the end result, you can learn to better understand the underlying mathematics.

You can also change how the trees are rendered, for example using mark instead of forward and by setting the width of the mark using setmarkerwidth depending on the current ‘size’ of the segment being rendered:

TO tree :s :a :frac :depth
   penup
   setpc item (remainder int :s 7) [11 9 4 12 14 8 13]
   if pencolor = 0 [setpc 8]
   setmarkerwidth 1 + :s / 20
   bk :s / 20
   mark :s / 2
   if :s >= 1 [
      local "p
      local "h
      make "p pos
      make "h heading
      left :a
      tree :s * 2 / 3 :frac * :a :frac :depth + 1
      pu setpos :p pd
      seth :h + :a
      tree :s * 2 / 3 :frac * :a :frac :depth + 1
   ]
END

cs tree 300 50 0.88 4

Et voila!