Alpine Trees: an Introduction to Terrain

turtleSpaces new terrain functionality provides some great opportunities for simple coding examples with few lines of Logo code, in this case less than 30.

First, we need to introduce the setterrain primitive. setterrain creates ‘terrain’ or a contiguous object of varying elevation.

The above is an example of the object created by setterrain. The setterrain primitive takes a number of parameters, and is a good opportunity to explain the different types of parameters used in turtleSpaces to students.

The setterrain command used to create the above is:

setterrain [-5 -5 5 5] [0 50 10 40] random 1000 [fbm 2] “voxel

As you can see, the command has a number of different parameters.

The first parameter is a list containing the number of quadrants (blocks of ten elevation points, by default spaced one turtle-unit apart) in each direction from [0 0], the center of the turtleSpace, expressed as X Y pairs.

So, in this case, we are creating a grid of 25 quadrants in each of the four directions (forward/left, back/left forward/right back/right) surrounding [0 0], for a total of. 100 quadrants.

The second list contains four values: The elevation (or z value) of the ‘bottom’ of the terrain, the elevation of the highest points of the terrain mathematically generated, the ‘floor’ of the terrain which is the lowest level of the generated terrain rendered (so you can create lakes) and the ‘ceiling’ of the terrain which is the highest elevation of the generated terrain rendered (so you can create plateaus).

You can use the setterraincolors primitive to set the colors of various elevations, but this is beyond the scope of this article.

The third parameter is the ‘seed’ of the terrain generator. In the case of our example, we are using the random function to generate a random number to use as the seed, to create a different terrain each time we execute the command. But you can use an absolute number, eg 433, which will create the same terrain every time. This allows you to build additional objects on the terrain and ensure that terrain is the same every time you execute your program.

The fourth parameter, the algorithm used to generate the terrain, is a chameleon of sorts: it can either take a list or a word value depending on your intent. You can provide just a word, eg “fbm (the only algorithm type currently available) or a list, eg [fbm 2] — the second value in the list provides the ‘magnification’ of the algorithm. The larger the number, the less dense the terrain will be in terms of peaks and troughs. If you use a fraction eg 0.2 then the terrain will become more dense, to the point of looking more like a cityscape then terrain!

The final parameter is a word that specifies the style. There is currently only one style, voxel, hence the parameter in our example is “voxel

And so, as you can see, we have lists, numbers and words all as parameters passed to setterrain.

You can play with these values a bit and see the results. Be aware that you need to either call reset or clearterrain (not clearscreen, which does not affect terrain) before you execute the setterrain command again, because you cannot ‘overwrite’ existing terrain. But keep in mind you can create different blocks of terrain in different areas, so long as they do not overlap!

The voxels in the terrain by default are only one turtle-unit cubed, which are very small, You can increase the size of the voxels used in the terrain by using the setterrainresolution primitive to change that size, eg setterrainresolution 10. This will expand the size of the terrain by a factor of 10, so keep in mind your camera may end up ‘inside’ the terrain and you will need to use the scroll wheel on your mouse to pull the camera to the outside of it. Or you could use commands like:

cam:setorbitdistance 1000

cam:orbitdown 60

which pulls the camera turtle away from the center point and ‘orbits’ it down 60 degrees, cam: denoting that we are talking to the camera turtle, by default ‘snappy’ (if you use the setview primitive to change the camera turtle, then cam: commands that turtle instead.)

And so the start of our program looks like this:

TO trees
  reset hideturtle penup
  setterrainresolution 10
  
  setterrain [-5 -5 5 5] [0 50 10 40] random 1000 [fbm 2] "voxel
  ;create random terrain
  
  cam:setorbitdistance 1000
  cam:orbitdown 60
  ;position camera
END

and results in this:


And so we have our terrain, which is by default all white and suits our purposes. But now we need to put trees on it!

Our trees are made up of cylinders, of varying size and side counts, to provide variety. A random icosphere adorns the top of each tree.

First, we’ll create a repeat loop of 100, to create 100 trees:

repeat 100 [

]

The lines between the square brackets are where we’ll put the lines we want to repeat. Next we want to position the turtle in a random spot on the terrain, but we want the treeline to be at least 200 turtle-units on the positive Z axis.

We’re going to be using the elevation primitive, which returns the elevation at the given x and y co-ordinates expressed as the z co-ordinate of the elevation NOT the voxel count (remember, we’ve set the terrainresolution to 10, which means the actual z co-ordinate will be 10 times the voxel count).

We’re also going to be using dountil, which repeats an action until the condition provided to it is satisfied. And so we’re going to position the turtle in random spots within the area of the terrain and measure the elevation there, only continuing if the elevation is 200 or greater:

    dountil 200 < elevation pos [
      setxy -480 + random 960 -480 + random 960
    ]

Once we’ve found an appropriate spot, we’re going to set our elevation to the top of the terrain and flip the turtle upwards 180 degrees, because cylinders are created beneath the turtle:

    setz elevation pos up 180

We need to pick a color for the trunk (8 is brown and 9 is orange) and a random shade:

    setfillcolor pick [8 9]
    randomfillshade

Next we’ll create containers containing randomly-generated values determining the size of the tree and the number of sides it has:

    make "size 5 + random 20
    make "sides 3 + random 20

We’ll use the values contained in these containers in our cylinder commands to create our tree appropriately. Next we make the trunk based on these values:

    cylinder :size / 2 2.5 * :size :sides

cylinder takes three parameters: the radius of the cylinder, the depth of the cylinder and the number of sides. :size returns the value stored in the “size container, similarly with :sides.

Next we’ll lower the turtle to the end of the cylinder:

    lower 2.5 * :size

Now comes the creation of the tree’s ‘foliage’. First we need to select the tree’s color, then create 20 cylinders making up the foliage, then place a randomly-colored icosphere on the top.

    setfillcolor pick [4 12 14]

4, 12 and 14 are greenish colors.

repeat 20 [

]

We’re going to make 20 cylinders. Inside the repeat loop we place the following:

      setfillshade 15 - 1.5 * repcount
      cylinder 2.5 * :size - ((2.5 * :size) / 20) * repcount :size / 4 :sides
      lower :size / 4
      right 90 / :sides

repcount returns the current repeat ‘loop’ we’re in, and so first we set the fill shade (fill colors are used by shape primitives such as cylinder) based on the repeat loop. Second we create the cylinder, third we lower the turtle to the bottom of the cylinder, and finally we turn the turtle right based on the number of :sides the cylinder has, creating the spiral effect.

    randomfillshade randomfillcolor
    raise :size / 4 lower :size / 5
    icosphere :size / 5 up 180

Next, we set a random fillshade and fillcolor, raise the turtle back up so that we can lower it with a more appropriate value for our icosphere, then create the icosphere based on the :size value. Finally, we create the icosphere. Then we repeat all of this 100 times for 100 trees, ending up with something like this:

Here is the listing in full:

TO trees
  reset hideturtle penup
  setterrainresolution 10
  ;the terrain resolution affects all terrain! If you change it, terrain is regenerated.
  
  setterrain [-5 -5 5 5] [0 50 10 40] random 1000 [fbm 2] "voxel
  ;create random terrain
  
  cam:setorbitdistance 1000
  cam:orbitdown 60
  ;position camera
  
  ;create 100 trees:
  repeat 100 [
    dountil 200 < elevation pos [
      setxy -480 + random 960 -480 + random 960
    ]
    ;position the turtle someplace where the elevation is 200 or greater
    
    setz elevation pos up 180
    ;raise the turtle to that elevation and flip it on its back
    
    setfillcolor pick [8 9]
    randomfillshade
    ;select trunk color / shade
    
    make "size 5 + random 20
    make "sides 3 + random 20
    ;select random values
    
    cylinder :size / 2 2.5 * :size :sides
    ;make the trunk
    
    lower 2.5 * :size
    setfillcolor pick [4 12 14]
    ;select foliage colors
    
    repeat 20 [
      ;create 20 'rings'
      setfillshade 15 - 1.5 * repcount
      cylinder 2.5 * :size - ((2.5 * :size) / 20) * repcount :size / 4 :sides
      lower :size / 4
      right 90 / :sides
      ;this creates a spiral effect in the tree
    ]
    
    randomfillshade randomfillcolor
    raise :size / 4 lower :size / 5
    icosphere :size / 5 up 180
    ;make the 'ball' on top
  ]
END

Don’t forget that you can click and drag the mouse to move the camera around the model, and scroll in and out to zoom!

 

Activity Idea: Gone Fishin’

Build this cool island scene using turtleSpaces Logo and a few basic shapes!

First we begin with a tree. We can build a trunk using a repeat loop of cylinders that get narrower in diameter and longer as we go. We can introduce a slight curve as well by tilting the turtle up a bit each cylinder we create:

Next we need to create the leaves, which we can do using the fiso (filled triangle) primitive. We can use a repeat loop to create a series of triangles growing in size, and then a second repeat loop to create a further series of triangles shrinking in size. In both cases, we tilt the turtle down a bit each triangle we create:

Then we can use a further wrapping repeat loop to create 8 of them around the trunk:

Let’s add six coconuts to the top of the tree using another repeat loop and icospheroids:

But one tree is kind of lonely, so let’s create a ring of eight around the edge of the island using the orbitleft primitive. We can also make the island more mound-like using a domoid:

Let’s add a dock Myrtle can fish off of made out of cylinders and voxeloids:

And a hut to shelter in made out of made out of a cutsphereslice and a sphereslice:

Myrtle’s all set, let’s get her fishing! The fishing rod is created using a thick line and a thin line:

The sunset effect is created using an inverted gradient tube:

Good job, Myrtle! You can check out the island yourself at https://turtlespaces.org/weblogo/?pub=64

Just click the flag to create the island. Don’t forget that you can click and drag on the viewport to move the camera, use the scroll wheel to zoom in and out, rotate using the right button and drag, and click both buttons and drag to pan.

Check out the code to see how it’s done! Then try something similar yourself. What will your island look like? Share it so we can see for ourselves!

turtleArt Thumbtack String Corkboard

This commented Logo source code creates a thumbtack, a cork board, and then draws random string art using them.

Read the ;comments to learn more about what the primitives do and what their shortcuts are.

Try some of the primitives out in turtleSpaces interactive mode (the myrtle prompt) and see what they do!

You can drag-select the source code and then paste it into the turtleSpaces editor (which you enter by typing ed and Enter or pressing control-shift-E) using control-shift-V (paste)

Then exit back to interactive mode using control-shift-O (save) and then type stringart and Enter to execute it.

Change elements of the code and see what happens!

TO tack
  ;create a thumbtack, or pushpin
  
  setfillcolor pick without 5 without 10 range [1 15]
  ;pick a number between 1 and 15 except 5 and 10
  
  cylinder 4 2 20
  ;cylinder takes width depth sides
  
  lower 2
  ;lowers the turtle eg moves beneath it
  
  cutcone 2 3 7 20
  ;cutcone takes topwidth bottomwidth depth sides
  
  lo 7
  ;lo is shortcut for lower
  
  cylinder 4 2 20
  lo 2
  setfc pick [5 10]
  ;setfc is shortcut for setfillcolor, the color
  ;used for painting shapes
  
  cylinder 1 5 8
  lo 5
  cone 1 1 8
  raise 16
  ;raises the turtle, eg moves above it
  ;all done!
  
END

TO corkboard
  ;create a corkboard to push our pins into
  
  penup
  setpos [-205 -116]
  
  setfillcolor 8 setfillshade -4
  ;setfillshade takes a range of -15 to 15
  
  forward 5 lo 3 slideright 5
  voxeloid 400 222 4
  ;voxeloid takes width height depth
  ;this creates the surface of our corkboard
  
  slideleft 5 ra 3 back 5
  setfs 6
  ; setfs is shortcut for setfillshade
  
  voxeloid 10 232 10
  ;this and subsequent voxeloids
  ;create the frame
  
  right 90
  sl 10
  ;sl is shortcut for slideleft
  
  voxeloid 10 410 10
  fd 400
  ;fd is shortcut for forward
  
  left 90
  bk 10
  ;bk is shortcut for back
  
  voxeloid 10 232 10
  fd 222 lt 90 bk 10
  ;lt is shortcut for left
  
  voxeloid 10 410 10
  ;that's all folks!
  
END

TO stringart
  reset
  ;resets the workspace
  
  snappy:run pick [
    [pullout 10]
    [pullout 30 orbitdown 70]
    [orbitleft 20 orbitdown 45 rollright 10 pullout 60 rr 10 sl 25 lo 40]
    ;rr is shortcut for rollright
    [orbitright 20 orbitdown 45 rollleft 10 pullout 60 rl 10 sr 25 lo 40]
    ;rl is shortcut for rollleft
  ]
  ;pick a camera sequence and execute it as
  ;snappy, the camera turtle
  
  ;if we need snappy to do more sophisticated
  ;things, we can store procedures inside him
  
  ;logo is all about having the freedom to do
  ;things in multiple ways!
  
  setpenwidth 1 + random 5
  ;sets the 'width' of the pen, from 1 to 5
  
  randps
  randfs
  ;randps and randfs (aka randompenshade and randomfillshade)
  ;set a random shade between -12 and 12
  
  penup
  corkboard
  ;execute corkboard procedure
  
  repeat 20 + random 20  [
    ;do the following 20 + 0-19 times:
    
    randpc
    ;shortcut for randompencolor
    
    setpos {-190 + random 380 -100 + random 200}
    ;move to a random position
    
    pu
    ;pu is shortcut for penup
    
    pushturtle
    ;save the turtle state on the 'stack'
    ;you can have multiple states on the stack
    
    raise 10 + random 4 up -10 + random 20 rr -10 + random 20
    ;move into a semi-random position
    ;to give our tacks a more natural-looking
    ;placement
    
    ;moving in negative values moves the opposite
    ;direction, eg left -90 turns right 90 degrees
    
    tack
    ;execute tack procedure
    ;(create a tack)
    
    popturtle
    ;load the turtle state from the 'stack'
    ;this puts it back where and how it was when
    ;we pushed it
    
    pendown
    ;pd is shortcut for pendown
    ;this will cause us to create a line to the
    ;next random position
    
  ]
  ;repeat the above however many times
  ;specified by 20 + random 20
  
  hideturtle
  ;ta da!
  
  ;for extra credit, get some tacks, a corkboard, and some
  ;colored string and make some string art of your own!
  
  ;consider the angles the turtle would need to turn to travel
  ;along the line of string created between all the pins
  ;were the turtle to travel the string like driving
  ;down a road
  
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