L-Py Turtle explanation

Initial orientation of turtle’s frame

Global reference frame (X,Y,Z) of L-Py (A).

The Turtle reference frame (H,L,U) is defined in (B) and can be displayed using primitive Frame

Axiom: Frame

Visualize the turtle reference frame

Default angle is 60° ( + is identical to +(60) )

Axiom: FF[+ FF]FFF                          # Original code (A)

Axiom: Frame FF[+ FF Frame ]F Frame FF      # New code with Frames (B)

Rotating with HLU

Primitives can be used to rotate the turtle in its current reference frame (H = Head, L = Left, U = Up, angles are expressed by default in degrees).

Axiom: Frame /(60) Frame     # Around turtle's Head

Axiom: Frame ^(60) Frame     # Around turtle's Left arm (note that the rotation is indirect)

Axiom: Frame +(60) Frame     # Around turtle's Up side

Drawing Polygons

Basic method

Turn and move forward

Axiom: Frame(2)+(30)F(5)+(120)F(5)+(120)F(5)  # (A)

Procedural method

A loop construct can be used to produce the L-string specifying the polygon

Axiom: Frame(2)+F(5)+F(5)+F(5)+F(5)+F(5)+F(5)  # (B)
# Or equivalently:
    nproduce Frame(2)
    for i in range(6):
        nproduce +F(5)

Filled polygon

Polygon can be drawn by using {} and positioning a series of dots (‘.’) in space, corresponding to the consecutive vertices of the polygon (A)

Here, the instruction starts by positioning the first vertex of the polygon at the origin of the reference frame

Axiom:  _(0.05),(2){.f(3).-(90)f(3).-(90)f(3).-(90)f(3)}

The contour of the polygon can be drawn by using F instead of f. In this case, dots (.) are no longer required after each F (B)

Axiom:  _(0.05),(2){.F(3)-(90)F(3)-(90)F(3)-(90)F(3)}

The number of edges drawn can be different from the number of vertices (C)

Axiom:  _(0.05),(2){.F(3)-(90)F(3)-(90)F(3)}

Note that if the first dot/point is omitted, the polygon is not closed (D)

Axiom:  _(0.05),(2){F(3)-(90)F(3)-(90)F(3)}

Filling concave objects requires to use a smarter filling procedure. This can be acheived by using a True argument to the polygon drawing (by default the argument is False)

# Naive procedure to fill the concave form: (A)
Axiom: _(0.01),(2) {.F+(95)F(0.7)-(120)F(0.2)+(80)F-(120)F(0.2)+(80)F(0.5)
-(120)F(0.5)+(80)F(0.2)-(120)F(0.5)+(150)F-(120)F(0.3)+(80)F -(120)F+(80)F(0.3)
-(120)F +(150)F(0.5)-(120)F(0.2)+(80)F(0.5)-(120)F(0.5)+(80)F(0.2)-(120)F+(120)F(0.2)
# while with a smarter procedure: (B)
Axiom: _(0.01),(2) {.F+(95)F(0.7)-(120)F(0.2)+(80)F-(120)F(0.2)+(80)F(0.5)
-(120)F(0.5)+(80)F(0.2)-(120)F(0.5)+(150)F-(120)F(0.3)+(80)F -(120)F+(80)F(0.3)
-(120)F +(150)F(0.5)-(120)F(0.2)+(80)F(0.5)-(120)F(0.5)+(80)F(0.2)-(120)F+(120)F(0.2)

Branching system

Bracket makes it possible to specify branches. Before each opening bracket, the turtle parameters (represented by the Frames) are stored on the Turtle stack. These parameters are then pop back when a closing bracket is found.

Axiom: F(2) [+F[-F(0.5)]F(0.5)] F [-F] F

The same branching system can be augmented with other modules (@**O** for sphere, …)

Axiom: F(2) [+F[-F(0.5);(3)@O(0.2)]F(0.5);(3)@O(0.2)] F[-F;(3)@O(0.2)] F;(3)@O(0.2)


Drawing a straight line made of length l=10 with segments of size dl = 1.0 (and thus contains n= 10 segments) (A)

Axiom: nF(10, 1.)

By adding the primitive SetGuide before the line drawing, it is possible to specify a curve on which the turtle is moving (instead of heading straight).

The SetGuide primitive must be given two mandatory arguments: a curve (Polyline2D or NurbsCurve2D) and a length: SetGuide(C0, L0). This means that, following this statement, the turtle will move on curve C1 that has been rescaled from C0 so that its new length is L0 (whatever its original length).

The guiding curve can be defined in different ways. It can be defined for example by a python function (function f defined hereafter), e.g. (B) :

from openalea.plantgl.all import Polyline2D
from numpy import arange

def f(u):
  return (u,u**2)

C0 = Polyline2D([f(u) for u in arange(0,1,0.1)])  # (B)

or using the embedded L-Py graphical interface for specifying 2D curves (the curve is then given the name C0 for instance in the interface):


Then using curve C0 in the SetGuide primitive, one can move the turtle over a cumulated length L, thus using the defined curve C1 (rescaled from C0) as a guide for moving up to a total length L0 (C):

L = 10
L0 = 10
Axiom: SetGuide(C0,L0) nF(L, 0.1)

Note that the turtle can move less than the length of the 2D curve. In this case it will proceed forward over the L first units at the beginning of curve C1 (B). By contrast, if L > L0, then the turtle keeps on moving straight after reaching length L0 (C).

L = 6
L0 = 10
Axiom: SetGuide(C0,L0) nF(L, 0.1)  # (B)

L = 15
L0 = 10
Axiom: SetGuide(C0,L0) nF(L, 0.1)  # (C)

Color System

To use color system, it is necessary to set materials with the Color Map window (Color Map).

The semicolon (‘;’) is use to increase the current material index (A) and the comma (‘,’) to dricrease it (B). A parameter can be set to specify the index of the material to use.

Axiom: F(2) ; @O(0.2)  # (A)
# Or equivalently:
Axiom: F(2) ;(2) @O(0.2)

Axiom: F(2) , @O(0.2)  # (B)
# Or equivalently:
Axiom: F(2) ,(0) @O(0.2)

The second manner to set color to an object is to use SetColor. There is two way to use it. The first way is to specify the index of the material (A) and the second way is to set the rgb (or rgba) values in parameters (B).

Axiom: F(2) SetColor(5) @O(0.2)             # (A)

Axiom: F(2) SetColor(45, 200, 200) @O(0.2)  # (B)

The last manner to use the color system is to use InterpolateColors, it use to mix up two colors in one. There is three parameter, the first and the second are the index of materials and the last is optional and it use to set a priority to the first or the second color to make the final color.

Axiom: F(2) InterpolateColors(1, 5) @O(0.2)       # (A)

Axiom: F(2) InterpolateColors(1, 5, 0.2) @O(0.2)  # (B)

Axiom: F(2) InterpolateColors(1, 5, 0.8) @O(0.8)  # (C)