Theory
| Flea l-systems do not use the terse legacy l-system
notation, where + means "right"
and - means "left", etc. Any
legacy l-system can express in Flea as a very narrow
subset of the language Ruby, using objects
as Axioms and method calls on these objects as
Actions.
In theory, you can write l-systems without learning
Ruby. In practice, there are just a few Ruby statements
that make writing l-systems easier - statements
to loop over ranges, declare scalar variables,
perform mathematical operations, etc.
Those seeking deeper Ruby enlightment should start
here:
http://www.ruby-lang.org/en/doc.html
|
Globals
| Support items available to all .flea scripts, but a
method of no overt object. |
egg = Ovum.new | Our
SystemMetaphor is
DNA in a spore, seed, or egg. The class that contains all Axioms
(as if they were nucleotide molecules) is therefor an
"Ovum". Start .flea scripts by creating a "new"
object from this class. As a convention we name this
object an "egg" (because that's
a short but complete name), but you can call it anything you like.
An Ovum begins life at the 0,0,0 location with a vector pointing
up. This direction is Z internally, but the Flea console programs
(fleaPOV, fleaVRML, etc.) will translate this into the back-end
program's coordinate system. |
egg = Ovum.new
egg.RecursionDepth = 2
egg.DefaultAngle = 90
egg.DefaultThickness = 50
ax = egg.newRootAxiom ('A')
ax.longer(8).tube
render egg
|
|
$fast | Senses the command-line option +fast setting, where
+fast is true and -fast is false. Use this to tune
your scripts so quick
thumbnails don't take forever to calculate. fleaTk
sets this to true by default. |
depth = if $fast then 4 else 8 end
egg = startOvum (depth, 60, 80)
root = egg.newRootAxiom ('Q')
ax = egg.newAxiom ('A')
root.longer(7).gosub(ax)
ax.shorter(0.5).tube.
push.right.link(ax).pop.tube.
push.right.link(ax).pop.left.link(ax)
render egg
|
|
render egg | After declaring an egg and its DNA hatch it here. |
egg = startOvum (6, 60, 80)
root = egg.newRootAxiom ('Q')
ax = egg.newAxiom ('A')
root.move.move.move.move.move.color(White).longer(2).
push.link(ax).pop.right.
push.link(ax).pop.right.
push.link(ax).pop.right.
push.link(ax).pop.right.
push.link(ax).pop.right.
push.link(ax).pop.right
ax.shorter(0.5).tube.tube.
push.right.link(ax).pop.
push.left.link(ax).pop.
push.longer(2).link(ax).pop.
push.right(180).link(ax).pop
render egg
|
|
Methods
| The token "ax " is not required. It's a common variable name for
Axiom,
which is a list of Actions for the Turtle to execute.
The "Turtle" represents a location in R3 and
a vector; a direction the turtle is going. The
naming system derives from "Turtle Graphics", a
common system to define shapes as commands in
simple languages.
Elements inside [brackets] are optional, and given
ax.yo[(keyword = 0)] the "keyword ="
part is apocryphal. Don't write it in a real .flea
script.
The Ruby parser reads lines delimited by linefeeds,
except where a line ends with a trailing operator.
That's why a dot followed by a linefeed should break
long lists of actions - not a linefeed followed
by a dot. Do this:
ax.method. method
Not this:
ax.method .method
by
|
povray.setMaterial(idx, pigment)
| The token "povray " is the object that
render will use. Set idx to a number
between 0 and 15, and pass in any
string that POVray perceives as a
pigment, texture or media. |
povray.setMaterial( 1,
'texture { T_Wood9 rotate x*45 scale 700 }' )
egg = Ovum.new
egg.RecursionDepth = 2
egg.DefaultAngle = 90
egg.DefaultThickness = 150
ax = egg.newRootAxiom ('A')
ax.longer(8).color(1).tube
render egg
|
|
ax.color [(index)] | Sets the index into the table declared by setMaterial,
or increments the index if none is provided. .tube ,
polygons and .sphere sense this setting when they
render.Currently limited to the range 0 to 15
inclusive; a future version will provide unlimited
ranges. |
egg = startOvum (2, 30, 100)
tubes = egg.newRootAxiom ('A')
tubes.longer(3).tube.color.tube.
color.tube.color(12).tube
render egg
|
|
ax.decAngle [(ratio = 0.9)] | Multiplies the default
angle by the given ratio. |
ax.down [(angle)] | Pitches that flying turtle down by the DefaultAngle or a given angle. Does not move the current turtle point. |
egg = startOvum (18, 30, 50)
ax = egg.newRootAxiom ('A')
r = egg.newAxiom ('R')
l = egg.newAxiom ('L')
u = egg.newAxiom ('U')
d = egg.newAxiom ('D')
ax.color(8).longer(5).
push.color(2).gosub(d).pop
ax.push.gosub(l).pop
ax.push.gosub(u).pop
ax.push.gosub(r).pop
r.right.tube.shorter(0.6).link(r)
l.left.tube.shorter(0.6).link(l)
u.up.tube.shorter(0.6).link(u)
d.down.tube.shorter(0.6).link(d)
render egg
|
|
ax.endPolygon | End recording polygon vertices. The current vertice is
not recorded. The resulting "polygon" represents
triangles drawn from the first vertice to each
successive pair of vertices. |
ax.gosub(ax) | Direct the turtle to execute the actions of
the target axiom.
Each call to .gosub does
not decrement the "depth" counter. If an axiom
.gosub 's to itself, directly or indirectly, an
infinite loop will break ruby, and the
egg.RecursionDepth will not save you. |
ax.half [(percent)] | calls ax.move (50) or ax.move (percent), if supplied. |
ax.halfTube [(percent)] | calls ax.tube (50) or ax.tube (percent), if supplied. |
egg = startOvum (2, 30, 100)
ax = egg.newRootAxiom ('A')
ax.longer(4).tube.color.halfTube.color.tube
render egg
|
|
ax.hop [(percent)] | Moves the turtle the current distance in the current direction. If called inside a .startPolygon / .endPolygon pair, the turtle does not record the new location as a polygon vertex. |
ax.horizontal | Imagine while flying an airplane you adjust the settings
so that little floating ball shows a level horizon... |
egg = startOvum (2, 30, 100)
ax = egg.newRootAxiom ('A')
wings = egg.newAxiom ('B')
ax.color(6).longer(2.5).right.right.
tube.gosub(wings).left.
tube.gosub(wings).left.
tube.gosub(wings).left.
tube.gosub(wings).left.
tube.gosub(wings).left.
tube.gosub(wings).
horizontal.
tube.gosub(wings)
wings.
push.
thinner.shorter(0.7).color(14).
push.
right(90).tube.
pop.
push.
left(90).tube.
pop.
pop
render egg
|
|
ax.incAngle [(ratio = 10 / 9)] | Multiplies the default
angle by the given ratio. |
ax.left [(angle)] | Banks that flying turtle to the left by the DefaultAngle or a given angle. Does not move the current turtle point. |
egg = startOvum (18, 30, 50)
ax = egg.newRootAxiom ('A')
r = egg.newAxiom ('R')
l = egg.newAxiom ('L')
u = egg.newAxiom ('U')
d = egg.newAxiom ('D')
ax.color(8).longer(5).
push.color(2).gosub(l).pop
ax.push.gosub(r).pop
ax.push.gosub(u).pop
ax.push.gosub(d).pop
r.right.tube.shorter(0.6).link(r)
l.left.tube.shorter(0.6).link(l)
u.up.tube.shorter(0.6).link(u)
d.down.tube.shorter(0.6).link(d)
render egg
|
|
ax.link(ax) | Direct the turtle to execute the actions of
the target axiom. Axioms may call themselves
directly or indirectly. Each call to .link decrements
a "depth" counter, and each return increments it.
The depth counter starts at the egg.RecursionDepth.
If the current value of "depth" is zero, link will
not call. Compare .gosub . |
povray.setMaterial( 1,
'texture { Copper_Metal scale 300 }' )
egg = startOvum (18, 45, 100)
ax = egg.newRootAxiom ('A')
b = egg.newAxiom ('B')
ax.longer(6).right.color(1).gosub(b)
b.tube.shorter(0.8).left.link(b)
render egg
|
|
ax.longer [(ratio = 10 / 9)] | Increments the current distance and current
thickness by multiplying them by the given ratio. |
egg = startOvum (2, 30, 100)
ax = egg.newRootAxiom ('A')
ax.longer(3).tube.color.
longer.tube.color.
longer(1.4).tube
render egg
|
|
ax.move [(percent)] | Moves the turtle the current distance in the current direction. If called inside a .startPolygon / .endPolygon pair, the turtle records the new location as a polygon vertex. |
ax.pop | Returns the turtle to the location, color,
vector & roll recorded on a LIFO stack by a previous
matched call to .push . |
ax.push | Records the turtle's current location, color,
vector & roll on a LIFO stack. The matched call
to .pop will return the turtle to this location. |
ax.random [(angle)] | TBD |
ax.right [(angle)] | Banks that flying turtle to the right by the DefaultAngle or a given angle. Does not move the current turtle point. |
egg = startOvum (18, 30, 50)
ax = egg.newRootAxiom ('A')
r = egg.newAxiom ('R')
l = egg.newAxiom ('L')
u = egg.newAxiom ('U')
d = egg.newAxiom ('D')
ax.color(8).longer(5).
push.color(2).gosub(r).pop
ax.push.gosub(l).pop
ax.push.gosub(u).pop
ax.push.gosub(d).pop
r.right.tube.shorter(0.6).link(r)
l.left.tube.shorter(0.6).link(l)
u.up.tube.shorter(0.6).link(u)
d.down.tube.shorter(0.6).link(d)
render egg
|
|
ax.roll180 | Calls either ax.rollRight (180) or ax.rollLeft (180). |
ax.rollLeft [(angle)] | Rolls the flying turtle left by the DefaultAngle or a given angle. This influences the meaning of the next .up , .right , .left or .down command. |
ax.rollRight [(angle)] | Rolls the flying turtle right by the DefaultAngle or a given angle. This influences the meaning of the next .up , .right , .left or .down command. |
ax.set(length) | Sets the current Distance setting to a non-relative
value. Use this, for example, to draw
fixed-size leaves on the ends of variable-size
twigs. |
ax.set(thickness) | Sets the current thickness to a non-relative
value. |
ax.shorter [(ratio = 0.9)] | Decrements the current distance and current
thickness by multiplying them by the given ratio. |
ax.sphere [(thickness)] | Creates a sphere centered on the current turtle point, colored the current setMaterial color. Does not move the current turtle point. The default thickness is the same as the current .tube default thickness. |
egg = startOvum (2, 30, 100)
ax = egg.newRootAxiom ('A')
ax.longer(5).tube.sphere.move(450).
color(10).sphere(2)
render egg
# observe how the lower sphere
# "caps" the end of its tube
|
|
ax.startPolygon | Begin recording polygon vertices. The current vertice
and all vertices at the ends of .move , .tube , .vertex ,
.half and .halfTube commands get recorded.
.endPolygon will render a polygon and clear the
vertice stack. |
ax.thicker [(ratio = 10 / 7)] | Multiplies the current
thickness by the given ratio. |
ax.thinner [(ratio = 0.7)] | Multiplies the current
thickness by the given ratio. |
egg = startOvum (2, 90, 100)
tubes = egg.newRootAxiom ('A')
tubes.color(6).right(45).longer(8).tube.left.
thinner.tube.left.
thinner.tube.left.
thinner(0.5).tube
render egg
|
|
ax.tropism [(gravity = 0.2)] | Warps the turtle's current vector "down" by
the given "gravity" factor. This effect senses
the turtle's current opinion of what "down" means.
If the turtle has rolled 180, say, "down" is up. |
egg = startOvum (20, 30, 50)
ax = egg.newRootAxiom ('A')
whip = egg.newAxiom ('W')
ax.push.down(8).longer(2).gosub(whip).pop.
rollRight(360/20).color.link(ax)
whip.tube.tropism(0.4).shorter.link(whip)
render egg
|
|
ax.tube [(percent = 100)] | Draws a cylinder whose length is "percent" times the current distance setting (which starts at 100 arbitrary units), plus a 5% cosmetic fudge factor. Moves the current turtle point the current distance. |
egg = startOvum (1, 90, 100)
tubes = egg.newRootAxiom ('A')
tubes.longer(5).tube.tube.shorter.
push.right.tube.pop.
left.tube
render egg
|
|
ax.up [(angle)] | Pitches that flying turtle up by the DefaultAngle or a given angle. Does not move the current turtle point. |
egg = startOvum (18, 30, 50)
ax = egg.newRootAxiom ('A')
r = egg.newAxiom ('R')
l = egg.newAxiom ('L')
u = egg.newAxiom ('U')
d = egg.newAxiom ('D')
ax.color(8).longer(5).
push.color(2).gosub(u).pop
ax.push.gosub(l).pop
ax.push.gosub(r).pop
ax.push.gosub(d).pop
r.right.tube.shorter(0.6).link(r)
l.left.tube.shorter(0.6).link(l)
u.up.tube.shorter(0.6).link(u)
d.down.tube.shorter(0.6).link(d)
render egg
|
|
ax.up180 | TBD |
ax.vertex | Between a .startPolygon / .endPolygon pair, this
records the turtle's current location as a "corner"
of the polygon. |
|