L-System Renderer

Rendering of the Dragon Fractal

The L-system renderer available in the input menu allows one to take an L-system and render that system for various levels of substitution. In the example picture we see the rendering of the dragon L-system given here.

JFLAPs L-system renderer subscribes to the canonical "turtle" metaphor, that is, an imaginary entity that moves about in a world, turning this way and that, and marking its territory as it moves forward. Functionally it is similar to other L-system renderers that exist, but it has a few major differences from the majority I encountered:

Definition of an L-System

Parameters

During the definition of the L-system the user has the chance to define some parameters in the table of the L-system input pane to affect the initial state of the drawing environment. What follows are a list of all recognized parameters, their default value for the renderer if they are not defined, and how they are used.

Parameter Default Description
distance 15 Lines are drawn with length distance.
color black Lines are drawn with the color specified by color. Colors may be specified by name. The acceptable color names are black, blue, brown, cyan, darkGray, darkOliveGreen, darkOliveGreen2, dukeBlue, forestGreen, goldenrod, gray, green, lightGray, magenta, maroon, oliveDrab, orange, orangeRed, pink, purple, red, springGreen, violetRed, white, and yellow. Color names are case sensitive!

Additionally, one may specify a given color according to three numbers of the form a,b,c. If a, b, and c are all within the range of [0.0, 1.0], they are interpreted as hue, saturation, and brightness values respectively (where the hue range of 0 through 1 represents a full tour around the color wheel), and are used to define a color appropriately. If any of those values is outside of that range they are treated as standard red, green, blue respectively, with each channel value ranging in increasing intensity from 0 to 255 as is normal. For example, blue may be defined either as an HSB color by .667,1,1 or as an RGB color by 0,0,255.

polygonColor red Polygons are filled with the color specified by polygonColor. This parameter accepts the same value types as the color parameter.
angle 15 Whenever the turtle is turned, pitched, or rolled, it does with angle degrees. Note that this parameter may also be named by angleIncrement (a compatibility measure with my first implementation).
hueChange 10 When the command to increment the hue of the current drawing color is given the degrees the hue is turned is hueChange.
lineWidth 1.0 Lines are drawn with a pixel-width of lineWidth. This parameter accepts real number values greater or equal to zero (e.g., 4, 1.5, 0).
lineIncrement 1.0 When the line width (the parameter lineWidth) is incremented or decremented, it is incremented or decremented by this amount.

Drawing & Turtle Symbols

The following symbols are used to move the turtle about, and otherwise affect the state of the drawing. Whenever appropriate, a parameter will appear to indicate that the action associated with the symbol uses a quantity that can be changed. For example, & causes the turtle to pitch down by angle degrees. If the user has specified that angle=30, then the turtle will pitch down by 30 degrees.

Symbol Description
g Move forward distance in the y direction with the pen down, producing a line of width lineWidth and of color color, unless we are building a polygon, in which case a line is not drawn and the end point of this move is added to the polygon.
g(value) Like the above, but with a specified distance.
f Move forward distance in the y direction with the pen up, producing no line but changing the position of the turtle.
f(value) Like the above, but with a specified distance.
+ Turn right (clockwise in 2D) by angle degrees. Turns about the z-axis.
+(value) Like the above, but with a specified number of degrees.
- Turn left (counter-clockwise in 2D) by angle degrees. Turns about the z-axis.
-(value) Like the above, but with a specified number of degrees.
& Pitch down by angle degrees. Turns about the x-axis.
&(value) Like the above, but with a specified number of degrees.
^ Pitch up by angle degrees. Turns about the x-axis.
^(value) Like the above, but with a specified number of degrees.
/ Roll right by angle degrees. Turns about the y-axis.
/(value) Like the above, but with a specified number of degrees.
* Roll left by angle degrees. Turns about the y-axis.
*(value) Like the above, but with a specified number of degrees.
[ Begin branch (i.e. push turtle state on stack).
] End branch (i.e. pop turtle state from stack). If there is no corresponding [, this has no effect. Aside from restoring position and direction, any changes to variables since the last [ will be undone.
! Increment lineWidth by lineIncrement.
!(value) Like the above, but increments by the specified amount.
~ Decrement lineWidth by lineIncrement, with a minimum lineWidth of zero attainable.
~(value) Like the above, but decrements by the specified amount.
{ Begin the definition of a polygon. The turtle position when the { is processed will be the first point in the polygon, and the end point reached by each g directive until the close of the polygon will be added to the polygon.
} Ends the definition of a polygon. The turtle position when the } is processed will not be added to the polygon. The polygon will be filled with the color polygonColor and will have no outline.
% Turn by 180 degrees about the z-axis, the same axis as the + and - turns.
# Increments the hue angle of color by hueChange. Changing the hue angle will have no effect if color has no saturation, i.e., if color is black, grey, or white.
#(value) Like the above, but with a specified number of degrees.
@ Decrements the hue angle of color by hueChange.
@(value) Like the above, but with a specified number of degrees.
## Increments the hue angle of polygonColor by hueChange. Changing the hue angle will have no effect if polygonColor has no saturation, i.e., if polygonColor is black, grey, or white.
##(value) Like the above, but with a specified number of degrees.
@@ Decrements the hue angle of polygonColor by hueChange.
@@(value) Like the above, but with a specified number of degrees.
parameter=value This will attempt to set a parameter named parameter to value. For example, the symbol angle=20 will cause all subsequent turns to be made with 20 degrees, color=red will cause all subsequent g directives to produce red lines, and soforth. The names of parameters and acceptable values is the same as for the mappings in the parameter table. There must be no whitespace in the parameter=value symbol, or else it shall not be processed as a single symbol.

Values

You may have noticed that in the list of symbols were a number of symbols that take an argument, for example, the turn right symbol + can appear in the form +(value) to turn a specified number of degrees, and you can also say lineIncrement=value to set the amount the line width changes when the renderer encounters the symbols like ! and ~.

Every value may be as simple as a number, but it may be a mathematical expression involving parameters as values. One could say distance=distance+2, which will increment subsequent line lengths by 2. Moreover, if in the parameters list one specified that foo was 100, then the symbol g(3+(8+foo)/2) would yield a line of length 57. All g symbols are functionally equivalent to g(distance).

The operators allowed in a value are + (addition), - (subtraction), * (multiplication), / (division), ^ (power), ( and ) (parentheses), and they obey the usual rules of order of operations and soforth. If an undefined symbol appears in a mathematical expression, then a value of 0 is assumed for that symbol.

For higher performance, avoid the frequent use of expressions. For example, if you're curious about the relative performance of +(5*angle) versus + + + + +, the + + + + + will tend to be faster, though your milage may vary for your particular JVM.

Interface

The L-system renderer interface has 5 distinct components of interest.

3D Hilbert rendering with annotations

  1. While the system is busy rendering an L-system, the progress back will report the amount done to the user.
  2. This field will display the current symbols being drawn up to a point; since most interesting L-systems are exponential in their growth, this will usually be omitted since longer strings of symbols are usually quite nonsensicle to the user.
  3. This spinner allows the user to specify the depth of L-system substitution recursion. A level of 0 means that only the axiom will be rendered.
  4. The major portion of the view is used to display the rendering of the L-system. If the rendering extends beyond the extent of the view, scrollbars will appear to allow the user to inspect all of the rendering.
  5. Though of little use for 2D rendering, for L-systems that take advantage of 3D renderings the ability to look at the rendering from different angles is important. By twiddling these values the user can get a feel for the shape of the rendering.

Notes

The 3D "renderer," as it is, is nothing more than the standard Java 2D graphics where the z coordinate is ignored for drawing. Consequences of this are that all projections are orthogonal and that lines drawn over each other may not be in sensible depth order. Until either gl4java or (heaven forbid) Java3D becomes standard issue for the JVM on all reasonable platforms, this system shall persist.