Architecture Overview
This package bridges Plant MTGs with meshes and high‑performance visualization.
OPF/OPS files ──► read_opf/read_ops ──► MTG (MultiScaleTreeGraph)
│
▼
Reference Meshes (RefMesh)
│
▼
Geometry (ref_mesh + transform)
│
(lazy) refmesh_to_mesh per node
│
▼
Merge all meshes into a single Meshes.SimpleMesh geometry
│
▼
plantviz (Makie recipe) ──► Makie Figure/Axis
- Core types:
RefMesh
stores template geometry;Geometry
attaches aref_mesh
, a transform (Translate
,Rotate
,Scale
,Affine
, orSequentialTransform
), and an optional cached mesh to an MTG node attribute:geometry
. - IO:
read_opf
/read_ops
populate MTG nodes and scene transforms;write_opf
/write_ops
serialize meshes and transforms back to disk. - Computation: meshes are computed lazily; call
refmesh_to_mesh
to materialize. Matrix generation usesget_transformation_matrix
. At render time, node meshes are merged to a singleSimpleMesh
. - Visualization:
plantviz
builds on Makie’s ComputeGraph. It maps colors from attributes or user dictionaries viaget_mtg_color
/get_color
/get_colormap
, wires them as compute nodes withmap!
, and renders the merged mesh once.
Minimal example
using PlantGeom
opf = read_opf("test/files/simple_plant.opf")
fig, ax, plt = plantviz(opf) # visualize
Color Mapping & Caching
User input to plantviz(color=..., colormap=..., colorrange=...)
│
▼
get_mtg_color / get_ref_meshes_color get_colormap
│ │
▼ ▼
get_color_range ◄──────────── optional user colorrange
│
▼
Per-node color values (or per-refmesh/per-vertex inputs)
│ ┌─────────────────────────────────────────┐
├────────────►│ Cache: UUIDs-based attribute on MTG │
│ │ (e.g., :_cache_<hash>) holds Observables│
▼ └─────────────────────────────────────────┘
Makie plot attributes (colormap, colorrange, color per vertex)
│
▼
plantviz recipe renders via Meshes/Makie
- Inputs: single color,
Dict("RefMeshName" => color)
, attribute symbol (e.g.,:z_max
), or per-vertex arrays. A vector of colors/symbols per node is also supported; it expands to per-face colors using theface2node
mapping of the merged mesh. - Mapping:
get_colormap
resolves aColorScheme
;get_color_range
derives or validates ranges;get_color
maps values to colors. - Caching:
- Per-node color caches (UUID-derived Observables) for interactive updates when plotting per-node geometry.
- Scene cache on the root (
:_scene_cache
) as a single-entry NamedTuple(hash, mesh, face2node)
. Thehash
encodes the scene version and relevant options (filters). Invalidate withbump_scene_version!(mtg)
.
Rendering Model (Merged by Default)
- Build: traverses selected nodes, transforms ref meshes, materializes node meshes if needed, and merges them into one
SimpleMesh
for rendering. The merge is performed in a single pass for performance. - Colors: computes a single per-vertex color array and passes it to Makie. Attribute colors honor
colormap
andcolorrange
; dictionary inputs by refmesh are supported; per-vertex dictionaries pass through directly. - Mapping:
face2node
is stored alongside the merged mesh in:_scene_cache
to map triangles back to node IDs. This enables expanding per-node color vectors to per-face arrays. - Use:
plantviz(opf, color=:z_max)
; invalidate cache after geometry/attribute changes viabump_scene_version!(opf)
. The merged mesh andface2node
are reused across color updates.
Key Components
build_merged_mesh_with_map(mtg; ...)
: collects selected node meshes and returns(merged::SimpleMesh, face2node::Vector{Int})
. Theface2node
array maps each element of the merged mesh back to its originating node id.- Scene cache helpers:
scene_version
,bump_scene_version!
: version the scene to invalidate cache.scene_cache_key
: builds a stable key for the current selection/options.get_cached_scene
,set_cached_scene!
: retrieve/store a single cached scene(hash, mesh, face2node)
on the MTG root.
- PlantViz recipe (Makie): defines attributes (
color
,colormap
,colorrange
, etc.) and derives compute nodes withmap!
(:colorant
,:colormap_resolved
,:colorrange_resolved
,:index_resolved
). The plot calls into a helper that computes or retrieves the merged scene and computes vertex colors as needed.
Performance Notes
- Merging: performed in one pass; avoid repeated pairwise merges. Connectivity indices are reindexed with a running vertex offset.
- face2node: built with a single preallocated vector, filling by contiguous slices per node to minimize allocations.
- Colors: computed once per render and are not cached in the scene cache; only the merged mesh and face2node are cached to reduce invalidation churn.