# JSON file format and command-line interface for this program
## Basic command-line usage
```console
$ l-system-fractals filename.json
```
## `examples` directory
The `examples` directory has a number of JSON files and the resulting outputs.
## Basic idea for plotting
This program plots using [turtle
graphics](https://en.wikipedia.org/wiki/Turtle_graphics). At every time, the
turtle has a position and is pointing at a certain angle. The program will
interpret a string such as
```
A[-DA+C+A+C]+C-C-C+A[-DDDA[-DA+C+A+C]+C-C-C+A+CCC+A[-DA+C+A+C]+C-C-C+A+CCC]+CCC
-CCC-CCC+A[-DA+C+A+C]+C-C-C+A+BACBA[-DA+C+A+C]+C-C-C+ACCCBACB+A[-DA+C+A+C]+C-C-
C+A[-DDDA[-DA+C+A+C]+C-C-C+A+CCC+A[-DA+C+A+C]+C-C-C+A+CCC]+CCC-CCC-CCC+A[-DA+C+
A+C]+C-C-C+A+BACBA[-DA+C+A+C]+C-C-C+ACCCBACB
```
and turn it into a plot such as:
<img src="example1.svg" alt="A rectangular shape with squares removed and square islands around it" width="344" height="740" />
In this example:
- `A` and `C` instruct the program to draw forward 1.0 units from the turtle's
current location (moving the turtle)
- `B` instructs the program to draw forward 2.0 units from the turtle's current
location (moving the turtle)
- `D` instructs the program to move the turtle forward 1.0 units without drawing
- `[` instructs the program to push the current location and angle of the turtle
onto the stack
- `]` instructs the program to pop a location/angle pair of the stack and
position the turtle in that location pointing in that angle
- '+' instructs the program to rotate the turtle's heading by π/2 radians
(90°) clockwise
- '-' instructs the program to rotate the turtle's heading by π/2 radians
(90°) counter-clockwise
The magic happens when we apply rewriting rules to a given string. For example,
say we start with `A+B+A+B`, which corresponds to this shape:
<img src="example2.svg" alt="A rectangle" width="390" height="740" />
Next, suppose we apply the following rewriting rules:
- `A` ↦ `A[-DA+C+A+C]+C-C-C+A`
- `B` ↦ `BACB`
- `C` ↦ `CCC`
- `D` ↦ `DDD`
Then applying the rewriting rules once to the string `A+B+A+B` will result in:
```
A[-DA+C+A+C]+C-C-C+A+BACB+A[-DA+C+A+C]+C-C-C+A+BACB
```
The corresponding plot is:
<img src="example3.svg" alt="The rectangle above, except with a smaller square taken out of the top and bottom, and moved out to float one unit away" width="250" height="740" />
Applying the rewriting rules again gives us the initial example above.
## Commands
The structure of the JSON file depends on the _command_ you want to run. There
are three available commands:
- `PlotOne`: Make a plot of a specified iteration of the fractal
- `PlotMany`: Make a plot of several specified iterations of the fractal
- `OutputStrings`: Run the replacement rules on a string and output the string
to a file.
### `PlotOne` JSON structure
Use the `PlotOne` command to plot a single specified iteration of the fractal.
<img src="examples/koch.svg" alt="The 6th iteration of a Koch snowflake" width="707" height="800" />
A JSON file implementing the `PlotOne` command will have the following keys:
- `command`: the string `"PlotOne"` in this case
- `rules`: the rules given in the format described below
- `iteration`: an nonnegative integer, specifying how many times to iterate the
rewriting rules
- `plot_param`: the plot parameters in the format described below
- `filename`: a string with the desired filename of the resulting SVG
- `comment` (_optional_): a string, ignored by the program
#### Example
```json
{
"command": "PlotOne",
"rules": [...],
"iteration": 3,
"plot_param": [...],
"filename": "output_file.svg",
"comment": "blah, blah, blah"
}
```
### `PlotMany` JSON structure
Use the `PlotMany` command to plot a multiple specified iterations of the
fractal. The plots will be placed in a grid.
<img src="examples/hilbert.svg" alt="The first 6 iterations of a space-filling Hilbert curve" width="600" height="400" />
A JSON file implementing the `PlotMany` command will have the following keys:
- `command`: the string `"PlotMany"` in this case
- `rules`: the rules given in the format described below
- `iteration`: an nonnegative integer, specifying how many times to iterate the
rewriting rules
- `iterations`: a list of nonnegative integers, specifying how many times to
iterate the rewriting rules
- `row_len`: a positive integer specifying how many iterations to plot in each
row of the grid
- `plot_param`: the plot parameters in the format described below
- `filename`: a string with the desired filename of the resulting SVG
- `comment` (_optional_): a string, ignored by the program
#### Example
```json
{
"command": "PlotMany",
"rules": [...],
"iterations": [1, 2, 3, 4],
"row_len": 2,
"plot_param": [...],
"filename": "output_file.svg",
"comment": "blah, blah, blah"
}
```
### `OutputStrings` JSON structure
Use the `OutputStrings` command to apply rewriting rules to a string and write
the resulting string to a file.
A JSON file implementing the `OutputStrings` command will have the following
keys:
- `command`: the string `"OutputStrings"` in this case
- `rules`: an object mapping one-character strings to replacement strings, e.g.
`{"A": "AB", "B": "BAB"}`.
- `start`: the string on which to start iterating
- `iteration`: an nonnegative integer, specifying how many times to
iterate the rewriting rules
- `filename`: a string with the desired filename of the resulting text
- `comment` (_optional_): a string, ignored by the program
#### Example
```console
$ cat output_strings_example.json
{
"command": "OutputStrings",
"rules": {"A": "AB", "B": "BAB"},
"start": "A",
"iteration": 3,
"filename": "output.txt"
}
$ l-system-fractals output_strings_example.json
Output written to: output.txt
$ cat output.txt
ABBABBABABBAB
```
## `rules` formats
There are three formats for the `rules` field used by `PlotOne` and `PlotMany`,
increasing in complexity and flexibility: `Simple`, `Advanced`, and `Full`.
### `Simple` rules format
The `Simple` format provides the most basic specification syntax for rules. It
allows drawing line segments of one length (no moving without drawing),
specifying a single angle, and a single stack for location/angle pairs. The keys
appearing are:
- `type`: in this case, the string `"Simple"`
- `replacement`: an object mapping one-character strings to replacement strings, e.g.
`{"A": "AB", "B": "BAB"}`.
- `angle_numerator`, `angle_denominator`: these are used to specify an angle,
which will be π × `angle_numerator` / `angle_denominator`. The field
`angle_numerator` may be any integer, while `angle_denominator` must be a
positive integer.
- `start`: the initial string upon which to apply the replacement rules
When plotting the resulting string, the program will do the following for each
character:
- `+`: rotate clockwise by the specified angle
- `-`: rotate counterclockwise by the specified angle
- '[': push the current location and angle onto the stack
- ']' pop a location and angle pair off the stack, and set that as the current
location
- **all other characters** appearing as a key in `replacement`:
draw a line segment 1.0 units long from the current position in the direction
of the current angle
#### Example
This will implement a Koch snowflake:
```json
{ ...
"rules": {
"type": "Simple",
"replacement": {"A": "A+A--A+A"},
"angle_numerator": 1,
"angle_denominator": 3,
"start": "+A--A--A"
},
... }
```
### `Advanced` rules format
The `Advanced` format provides substantially more flexibility than `Simple`,
while still providing an easy syntax to use. It allows drawing line segments of
multiple lengths, moving the turtle without drawing for multiple lengths,
specifying a single angle, and a single stack for location/angle pairs. The keys
appearing are:
- `type`: in this case, the string `"Advanced"`
- `replacement`: an object mapping one-character strings to replacement strings,
e.g.
```json
"replacement": {
"A": "A[-DA+C+A+C]+C-C-C+A",
"B": "BACB",
"C": "CCC",
"D": "DDD",
},
```
- `draw_step_sizes`: an object mapping one-character strings to floating-point
numbers, instructing the program to draw forward that many units, e.g.
```json
"draw_step_sizes": { "A": 1.0, "B": 2.0, "C": 1.0 },
```
- `move_step_sizes`: an object mapping one-character strings to floating-point
numbers, instructing the program to move forward that many units without
drawing, e.g.
```json
"move_step_sizes": { "D": 1.0, "E": 2.0 },
```
- `angle_numerator`, `angle_denominator`: these are used to specify an angle,
which will be π × `angle_numerator` / `angle_denominator`. The field
`angle_numerator` may be any integer, while `angle_denominator` must be a
positive integer.
- `start`: the initial string upon which to apply the replacement rules
#### Example
This example produces an ["islands" fractal](examples/islands.svg) found in
Benoit B. Mandelbrot (1983), _The Fractal Geometry of Nautre (Updated and
Agumented)_, New York: W.H. Freeman
and Company, p. 121
```json
{ ...
"rules": {
"type": "Advanced",
"replacement": {
"A": "A+BA-AA-A-AA+B+AA-BA+AA+A+AA-B-AAA",
"B": "BBBBBB"
},
"draw_step_sizes": { "A": 1.0 },
"move_step_sizes": { "B": 1.0 },
"angle_numerator": 1,
"angle_denominator": 2,
"start": "A-A-A-A-"
},
... }
```
### `Full` rules format
The `Full` format provides the maximum-possible flexibility, but at the cost of
being the most verbose. The keys appearing are:
- `type`: in this case, the string `"Advanced"`
- `replacement`: an object mapping one-character strings to replacement strings,
e.g.
```json
"replacement": {
"A": "A[A{B<AX",
"B": "BBBB",
"X": "}+A{>+A<]+A["
},
```
- `assignment`: an object mapping one-character strings to draw actions,
described below, e.g.
```json
"assignment": {
"A": { "type": "DrawForward", "dist": 1.0 },
"B": { "type": "MoveForward", "dist": 1.0 },
"X": { "type": "Null" },
"[": { "type": "Push", "stack": 0 },
"{": { "type": "Push", "stack": 1 },
"<": { "type": "Push", "stack": 2 },
"]": { "type": "Pop", "stack": 0 },
"}": { "type": "Pop", "stack": 1 },
">": { "type": "Pop", "stack": 2 },
"+": {
"type": "RotateCW",
"numerator": 2,
"denominator": 9
}
},
```
- `start`: the initial string upon which to apply the replacement rules
#### Draw actions
A draw action specified as a JSON object, with the key 'type' used to specify
the type of draw action, and other keys depending on the action. The possible
actions are:
- `DrawForward`: Draw forward by the distance specified. The keys are:
- `type`: in this case, the string `"DrawForward"`.
- `dist`: a float
- `MoveForward`: Move forward by the distance specified, without drawing. The
keys are:
- `type`: in this case, the string `"MoveForward"`.
- `dist`: a float
- `Push`: Push the current position and angle onto the specified stack. The keys
are:
- `type`: in this case, the string `"Push"`,
- `stack`: a nonnegative integer, specifying the stack. (Using the `Full`
syntax is the only way to have multiple stacks.)
- `Pop`: Pop position/angle pair off the specified stack, and adopt it as the
current position and angle. The keys are:
- `type`: in this case, the string `"Pop"`,
- `stack`: a nonnegative integer, specifying the stack. (Using the `Full`
syntax is the only way to have multiple stacks.)
- `RotateCW`: Rotate clockwise by the specified multiple of π The keys are:
- `type`: in this case, the string `"RotateCW"`
- `numerator`: Any integer
- `denominator`: Any positive integer
The rotation will by clockwise by π × `numerator` / `denominator`.
There is no action for counter-clockwise rotation; simply use `RotateCW` with
the negative of the desired value.
- `Null`: Do nothing. The object is `{"type": "Null"}`.
_Implementation note:_ The `Full` rules syntax reflects the internal
representation of any set of rules.
#### Example
```json
{...
"rules": {
"type": "Full",
"replacement": {
"A": "A[A{B<AX",
"B": "BBBB",
"X": "}+A{>+A<]+A["
},
"assignment": {
"A": { "type": "DrawForward", "dist": 1.0 },
"B": { "type": "MoveForward", "dist": 1.0 },
"X": { "type": "Null" },
"[": { "type": "Push", "stack": 0 },
"{": { "type": "Push", "stack": 1 },
"<": { "type": "Push", "stack": 2 },
"]": { "type": "Pop", "stack": 0 },
"}": { "type": "Pop", "stack": 1 },
">": { "type": "Pop", "stack": 2 },
"+": {
"type": "RotateCW",
"numerator": 2,
"denominator": 9
}
},
"start": "+A+A+A+A+A+A+A+A+A"
},
...}
```
## `plot_param` format
The `plot_param` field is used to specify parameters for the resulting plotted
output for a `PlotOne` or `PlotMany` command. This is an object with the
following keys:
- `width`: a float specifying the maximum width of the SVG output
- `height`: a float specifying the maximum height of the SVG output
- `border`: a float specifying the width of a border around the resulting
fractal in the SVG
- `fill`: a string that will be written in the SVG as the CSS `fill` attribute
in an SVG `path` element
- `stroke`: a string that will be written in the SVG as the CSS `stroke` attribute
in an SVG `path` element
- `stroke_width`: a float that is written in the SVG as the CSS `stroke-width`
attribute in an SVG `path` element
- `background` (_optional_): a string; if provided, there will be a rectangle
with this string as its SVG `fill` attribute behind the image
### Example
```json
{...
"plot_param": {
"width": 600.0,
"height": 400.0,
"border": 5.0,
"fill": "none",
"stroke": "black",
"stroke_width": 0.5,
"background": "white"
},
...}
```
## Examples
### Quadric Koch island
- Reference: Benoit B. Mandelbrot (1983),
[_The Fractal Geometry of Nature (Updated and
Agumented)_](https://en.wikipedia.org/wiki/The_Fractal_Geometry_of_Nature),
New York: W.H. Freeman and Company, p. 50
```json
{
"command": "PlotOne",
"rules": {
"type": "Simple",
"replacement": { "A": "A+A-A-AA+A+A-A" },
"angle_numerator": 1,
"angle_denominator": 2,
"start": "A+A+A+A"
},
"iteration": 4,
"plot_param": {
"width": 1040.0,
"height": 530.0,
"border": 10.0,
"fill": "#6f6",
"stroke": "#0f0",
"stroke_width": 1.0,
"background": "#006"
},
"filename": "quadric_koch_island.svg",
"comments": "Benoit B. Mandelbrot (1983), _The Fractal Geometry of Nautre (Updated and Agumented)_, New York: W.H. Freeman and Company, p. 50"
}
```
<img src="examples/quadric_koch_island.svg" alt="A green radially-symmetric shape that looks sort of like a Koch snowflake but more complicated." width="550" height="550" />
### Hilbert space-filling curve
- Reference (for formulation as an L-system):
[Wikipedia](https://en.wikipedia.org/w/index.php?title=Hilbert_curve&oldid=1194248627#Representation_as_Lindenmayer_system)
```json
{
"command": "PlotMany",
"rules": {
"type": "Advanced",
"replacement": { "A": "+BF-AFA-FB+", "B": "-AF+BFB+FA-" },
"draw_step_sizes": { "F": 1.0 },
"move_step_sizes": {},
"angle_numerator": 1,
"angle_denominator": 2,
"start": "A"
},
"iterations": [1, 2, 3, 4, 5, 6],
"row_len": 3,
"plot_param": {
"width": 600.0,
"height": 400.0,
"border": 5.0,
"fill": "none",
"stroke": "black",
"stroke_width": 0.5,
"background": "white"
},
"filename": "hilbert.svg",
"comment": "L-system formuation from Wikipedia: https://en.wikipedia.org/w/index.php?title=Hilbert_curve&oldid=1194248627#Representation_as_Lindenmayer_system"
}
```
<img src="examples/hilbert.svg" alt="The first 6 iterations of a space-filling Hilbert curve" width="600" height="400" />
### Nonagon snowflake
> Everybody turns just in time to see the pentagon arrive<br />
> Counting up the sides, it is clear the pentagon has five<br />
> Chatting in the kitchen we see<br />
> There is a triangle whose sides number three<br />
> And is talking to the shape that has nine<br />
> Who is known as Nonagon
—["Nonagon"](https://youtu.be/z5m8BWk5LoQ), They Might be Giants
```json
{
"command": "PlotMany",
"rules": {
"type": "Full",
"replacement": {
"A": "A[A{B<AX",
"B": "BBBB",
"X": "}+A{>+A<]+A["
},
"assignment": {
"A": { "type": "DrawForward", "dist": 1.0 },
"B": { "type": "MoveForward", "dist": 1.0 },
"X": { "type": "Null" },
"[": { "type": "Push", "stack": 0 },
"{": { "type": "Push", "stack": 1 },
"<": { "type": "Push", "stack": 2 },
"]": { "type": "Pop", "stack": 0 },
"}": { "type": "Pop", "stack": 1 },
">": { "type": "Pop", "stack": 2 },
"+": { "type": "RotateCW", "numerator": 2, "denominator": 9 }
},
"start": "+A+A+A+A+A+A+A+A+A"
},
"iterations": [0, 1, 2, 3, 4, 5],
"row_len": 3,
"plot_param": {
"width": 700.0,
"height": 500.0,
"border": 20.0,
"fill": "none",
"stroke": "black",
"stroke_width": 0.5,
"background": "white"
},
"filename": "cphan2.svg"
}
```
<img src="examples/cphan2.svg" alt="Six iterations of some weird spirally snowfake thingy, which starts out as a regular nonagon, and gets more and more complicated" width="700" height="500" />