|
1 | 1 | Methods |
2 | 2 | ======= |
3 | 3 |
|
4 | | -This document describes the methods and algorithms used in the `lpy_treesim` project. |
| 4 | +`lpy_treesim` marries biologically inspired L-systems with rule-based care |
| 5 | +operations (tying, pruning, support placement) so you can synthesize |
| 6 | +orchard-ready tree geometries. This page explains how the major pieces interact. |
5 | 7 |
|
6 | | -L-System for Tree Generation |
7 | | ----------------------------- |
| 8 | +Prototype-driven L-System |
| 9 | +------------------------- |
8 | 10 |
|
9 | | -`lpy_treesim` uses the L-Py language to define the growth rules of the trees. L-Py is a Python-based implementation of L-systems, which are a type of formal grammar that can be used to model the growth of plants and other biological systems. |
| 11 | +`base_lpy.lpy` is the only grammar we execute at runtime. Rather than handcode |
| 12 | +every rule, it reads extern variables that point to Python classes in |
| 13 | +`examples/<TreeName>`: |
10 | 14 |
|
11 | | -The L-system used in `lpy_treesim` is defined in the `.lpy` files in the `examples` directory. These files contain the axiom and production rules that determine the structure of the tree. |
| 15 | +``prototype_dict_path`` |
| 16 | + Imports the shared `basicwood_prototypes` mapping. Each entry contains a |
| 17 | + `TreeBranch` subclass plus its `BasicWoodConfig`, which exposes stochastic |
| 18 | + bending, bud spacing, lengths, and colors. |
12 | 19 |
|
13 | | -- **Axiom**: The axiom is the initial state of the L-system. It is a string of symbols that represents the starting point of the tree. |
14 | | -- **Production Rules**: The production rules are a set of rules that specify how the symbols in the L-system are replaced over time. Each rule consists of a predecessor and a successor. The predecessor is a symbol that is replaced by the successor. |
| 20 | +``trunk_class_path`` |
| 21 | + The entry class that seeds the axiom. All other branches sprout from the |
| 22 | + prototypes configured on this trunk. |
15 | 23 |
|
16 | | -By iteratively applying the production rules to the axiom, the L-system generates a sequence of strings that represents the growth of the tree. |
| 24 | +``simulation_class_path`` / ``simulation_config_class_path`` |
| 25 | + Provide training-system-specific behaviors (e.g., UFO trellis vs. Envy |
| 26 | + spindle). The config dataclass is serialized and handed to the runtime |
| 27 | + simulation via `TreeSimulationBase`. |
17 | 28 |
|
18 | | -Pruning and Tying Algorithms |
19 | | ----------------------------- |
| 29 | +During each derivation step the grammar delegates to your Python classes to |
| 30 | +decide when buds break, which prototype to spawn, and how to orient each new |
| 31 | +segment. Because everything happens inside Python, you can use NumPy, random |
| 32 | +sampling, and heuristics tailored to your target cultivar. |
20 | 33 |
|
21 | | -`lpy_treesim` includes algorithms for pruning and tying the branches of the tree. These algorithms are used to control the shape and size of the tree. |
| 34 | +Tying, pruning, and supports |
| 35 | +--------------------------- |
22 | 36 |
|
23 | | -- **Pruning**: The pruning algorithm removes branches from the tree that are too long or that are growing in the wrong direction. This is done by defining a set of rules that specify which branches to remove. |
24 | | -- **Tying**: The tying algorithm connects branches of the tree together. This is done by defining a set of rules that specify which branches to connect and how to connect them. |
| 37 | +The base simulation loop interleaves three routines: |
25 | 38 |
|
26 | | -The pruning and tying algorithms are implemented in the `stochastic_tree.py` module. |
| 39 | +1. **Derive**: expand the L-system string using the prototype logic. |
| 40 | +2. **Tie**: after a configurable number of iterations (`num_iteration_tie`), the |
| 41 | + simulation attaches branches to the virtual support wires generated by |
| 42 | + `TreeSimulationBase.generate_points()`. |
| 43 | +3. **Prune**: after `num_iteration_prune`, branches that exceed thresholds (age, |
| 44 | + curvature, or spacing) are removed. The decision functions live inside |
| 45 | + `stochastic_tree.py` and can be augmented via your prototypes. |
27 | 46 |
|
28 | | -API Reference |
29 | | -------------- |
| 47 | +All three phases reuse the `ColorManager` so instance labels remain stable even |
| 48 | +after pruning removes geometry. |
30 | 49 |
|
31 | | -.. automodule:: stochastic_tree |
32 | | - :members: |
| 50 | +Batch export pipeline |
| 51 | +--------------------- |
| 52 | + |
| 53 | +`tree_generation/make_n_trees.py` wraps the grammar in a CLI tool: |
| 54 | + |
| 55 | +* Builds a fresh `Lsystem` object per tree and injects the extern dictionary. |
| 56 | +* Seeds Python's RNG per tree so stochastic decisions differ while still being |
| 57 | + reproducible when `--rng-seed` is provided. |
| 58 | +* Calls `sceneInterpretation` to convert the final string into a PlantGL scene. |
| 59 | +* Writes the mesh using `tree_generation.helpers.write`, which emits ASCII PLY |
| 60 | + with normals and color attributes. |
| 61 | +* Dumps `{namespace}_{tree_name}_{index:05d}_colors.json` containing the mapping |
| 62 | + from instance IDs to semantic roles (spur, branch, trunk, tie, etc.). |
| 63 | + |
| 64 | +The naming scheme caps at 99,999 trees per run; start a new namespace if you |
| 65 | +need more. |
| 66 | + |
| 67 | +Extending the system |
| 68 | +-------------------- |
| 69 | + |
| 70 | +To add a brand-new method (new pruning heuristic, new tie behavior), derive from |
| 71 | +the appropriate class in `simulation_base.py` or `stochastic_tree.py` and inject |
| 72 | +your class via the extern dictionary. Because all extern paths are strings, |
| 73 | +`make_n_trees.py` can consume any importable module without further code |
| 74 | +changes. |
0 commit comments