Skip to content

API

PlantGeom.AmapReconstructionOptions Type
julia
AmapReconstructionOptions

Configuration for AMAP-style reconstruction stages used by set_geometry_from_attributes!, reconstruct_geometry_from_attributes!, and rebuild_geometry!.

This type controls how PlantGeom interprets MTG columns beyond the base GeometryConvention: explicit coordinates, insertion fallback, biomechanical stages, allometry preprocessing, and order-based defaults.

In normal use, create it with the keyword constructor AmapReconstructionOptions(; ...) rather than by filling fields manually.

source
PlantGeom.AmapReconstructionOptions Method
julia
AmapReconstructionOptions(; kwargs...)

Build the options object that controls the AMAP-style reconstruction pipeline.

Pass this object through the amap_options= keyword of:

julia
set_geometry_from_attributes!(mtg, prototypes; amap_options=...)
reconstruct_geometry_from_attributes!(mtg, prototypes; amap_options=...)
rebuild_geometry!(mtg, prototypes; amap_options=...)

The constructor is organized around five kinds of settings:

  1. alias lists: which MTG columns should be read for a given semantic

  2. explicit-coordinate behavior: how XX/YY/ZZ and EndX/EndY/EndZ are interpreted

  3. orientation and biomechanical stages: azimuth/elevation, stiffness, plagiotropy, constraints

  4. allometry preprocessing: how missing size values are interpolated or propagated

  5. order-based defaults: how branching order can supply default insertion/phyllotaxy values

Most users only need a few keywords:

  • explicit_coordinate_mode

  • verticil_mode

  • insertion_y_by_order

  • phyllotaxy_by_order

  • order_override_mode

Keyword reference:

  • insertion_mode_aliases Column names used to read insertion mode (CENTER, BORDER, WIDTH, HEIGHT). Change this if your MTG stores the same concept under different names.

  • phyllotaxy_aliases Column names used to read phyllotaxy fallback. This is used mainly when insertion azimuth information is incomplete.

  • verticil_mode::Symbol=:rotation360 Controls sibling spread when XInsertionAngle is missing. Use :rotation360 to distribute siblings around 360 degrees, or :none to disable this automatic spread.

  • geometry_constraint_aliases Column names used to read geometric constraint specifications. Change this only if your dataset stores these constraints under custom names.

  • coordinate_delegate_mode::Union{Nothing,Symbol}=nothing Legacy alias for explicit_coordinate_mode. Prefer explicit_coordinate_mode in new code. If both are provided, they must agree.

  • explicit_coordinate_mode::Union{Nothing,Symbol}=nothing Controls how explicit coordinates are interpreted. Accepted values are:

    • :topology_default: XX/YY/ZZ sets the node base, but the node still behaves like a regular visible segment if endpoints are missing.

    • :explicit_rewire_previous: explicit coordinates act as control points that rewire the previous segment; the explicit node becomes a point-anchor.

    • :explicit_start_end_required: nodes with explicit coordinates are rebuilt strictly from start/end coordinates; incomplete endpoints are omitted.

    If omitted, the default is :topology_default.

  • azimuth_aliases, elevation_aliases Column names used for world-space azimuth/elevation stages. Use these only if your MTG provides explicit orientation overrides in world coordinates.

  • deviation_aliases Column names used for deviation-angle rotation. This is an extra world-space directional adjustment applied after the main insertion stage.

  • orthotropy_aliases Column names used for orthotropy-driven bending orientation. This is a heuristic biomechanical orientation stage and is usually only relevant for datasets that provide such measurements.

  • stiffness_angle_aliases Column names used for directly measured stiffness-angle values. When present, these take precedence over orthotropy-based bending direction.

  • stiffness_aliases Column names used for propagated stiffness values (Stifness/Stiffness). These are used to derive component bending when direct stiffness angles are not already present.

  • stiffness_tapering_aliases Column names used for stiffness tapering. This changes how curvature is distributed along the organ.

  • stiffness_apply_aliases Column names used for toggling stiffness propagation to component children. Set the corresponding MTG column to false when you want to disable that propagation for a node.

  • stiffness_straightening_aliases Column names used for straightening after a given relative position along the organ. Larger values preserve bending farther along the organ.

  • broken_aliases Column names used for "broken segment" semantics. This forces downstream component bending to collapse after the break threshold.

  • plagiotropy_aliases Column names used for plagiotropy projection. Use this when your reconstruction must be projected toward a preferred directional plane.

  • normal_up_aliases Column names used for the NormalUp projection stage. This is mainly useful for dorsiventral organs such as leaves, where you want the organ normal to stay oriented toward world +Z.

  • orientation_reset_aliases Column names used to reset the inherited local frame before insertion/euler stages. Use this when selected nodes should stop inheriting orientation from their parent frame.

  • insertion_aliases Extra alias list for insertion semantics. This mainly exists for AMAP compatibility where some datasets use a shorter Insertion name.

  • endpoint_x_aliases, endpoint_y_aliases, endpoint_z_aliases Column names used to read explicit endpoint coordinates. These matter only when your dataset supplies end coordinates or when explicit_coordinate_mode relies on them.

  • allometry_enabled::Bool=true Enables the AMAP-style allometry preprocessing pass. When true, PlantGeom can interpolate, propagate, or infer missing length/width/ height values before geometry stages.

  • allometry_interpolate_width_height::Bool=true If true, missing width/height values can be interpolated along an axis. Disable this if you want missing cross-section values to remain missing unless explicitly measured or propagated.

  • allometry_default_length::Real=1.0 Default length assigned to terminal nodes when allometry is missing and no better estimate is available.

  • allometry_default_width::Real=1.0 Default width assigned to terminal nodes when allometry is missing and no better estimate is available.

  • allometry_default_height::Real=1.0 Default height/thickness assigned to terminal nodes when allometry is missing and no better estimate is available.

  • order_attribute=:branching_order MTG attribute used to define branching order for order-based defaults. Change this if your graph already stores order under another attribute name.

  • auto_compute_branching_order::Bool=true If true, PlantGeom computes branching order automatically when the chosen order_attribute is missing. Disable this if your dataset already provides the values and you do not want automatic recomputation.

  • insertion_y_by_order=Dict{Int,Float64}() Mapping from branching order to default YInsertionAngle. Useful when higher-order axes should systematically be more erect or more horizontal.

  • phyllotaxy_by_order=Dict{Int,Float64}() Mapping from branching order to default phyllotaxy. Useful when phyllotaxy is partly defined by organ order rather than measured node by node.

  • order_override_mode::Symbol=:override Controls how order-based maps interact with measured attributes. Accepted values are:

    • :override: order-map values replace present node values

    • :missing_only: order-map values are used only when the node value is absent

Examples

Use explicit start/end coordinates strictly:

julia
opts = AmapReconstructionOptions(
    explicit_coordinate_mode=:explicit_start_end_required,
)

Use order-based insertion defaults without overwriting measured values:

julia
opts = AmapReconstructionOptions(
    insertion_y_by_order=Dict(2 => 35.0, 3 => 20.0),
    order_override_mode=:missing_only,
)

Use custom MTG column names for explicit coordinates:

julia
opts = AmapReconstructionOptions(
    endpoint_x_aliases=[:tip_x, :EndX],
    endpoint_y_aliases=[:tip_y, :EndY],
    endpoint_z_aliases=[:tip_z, :EndZ],
)
source
PlantGeom.BiomechanicalBendingTransform Type
julia
BiomechanicalBendingTransform(young_modulus, initial_angle, beam_length, tapering;
    n_samples=96, integration_steps=10, x_min=0.0, x_max=beam_length,
    up=(0, 0, 1), length_scale=100.0)

Non-linear transformation based on a simplified cantilever biomechanical model.

The transform bends local coordinates along +X according to the angle profile computed from final_angle and local_flexion. It can be used directly in Geometry or composed through transform_mesh!. x_min/x_max define how local x maps to the normalized [0, 1] profile.

source
PlantGeom.ComposedPointMap Type
julia
ComposedPointMap(maps...)
compose_point_maps(maps...)

Compose multiple point maps into a single callable map, applied from left to right (maps[1] then maps[2], ...).

source
PlantGeom.ExtrudedTubeGeometry Type
julia
ExtrudedTubeGeometry(path;
    n_sides=8,
    radius=0.5,
    radii=nothing,
    widths=nothing,
    heights=nothing,
    path_normals=nothing,
    torsion=true,
    cap_ends=false,
    material=RGB(220 / 255, 220 / 255, 220 / 255),
    transformation=IdentityTransformation())

Procedural geometry source backed by extrude_tube_mesh.

Unlike Geometry, this source does not reference a pre-existing RefMesh; the mesh is rebuilt from its path/section parameters whenever materialized (for example by scene merging).

source
PlantGeom.GenericGeometryJob Type
julia
GenericGeometryJob

Typed fallback job for additional geometry source types materialized through geometry_to_mesh(geom).

source
PlantGeom.Geometry Type
julia
Geometry(; ref_mesh<:RefMesh, transformation=IdentityTransformation(), dUp=1.0, dDwn=1.0)

A node geometry backed by a shared RefMesh plus a per-node transformation.

This is the classic OPF-style "instantiate once, transform many" geometry source. The materialized mesh is computed lazily via geometry_to_mesh.

source
PlantGeom.LaminaAnticlasticWaveMap Type
julia
LaminaAnticlasticWaveMap(; amplitude=0.06,
    wavelength=0.20, edge_exponent=1.5, progression_exponent=1.0,
    base_damping=4.0, phase_deg=0.0, asymmetry=0.0, lateral_strength=0.0,
    vertical_strength=1.0)

Point map for cereal-like anticlastic undulation. It applies opposite-signed deformation on the two sides of the lamina (for a given x, one margin goes up while the other goes down), with sinusoidal variation along blade length (+X) and amplitude growth toward margins (|Y|), while keeping the midrib stable (Y = 0). Coordinates are interpreted in a normalized unit frame (x ∈ [0, 1], |y| ≤ 0.5).

  • amplitude: peak local +Z displacement magnitude at margins.

  • wavelength: sinusoid wavelength along local +X.

  • edge_exponent: controls how sharply ripple grows from midrib to margins.

  • progression_exponent: controls wave growth from base to tip (u^p).

  • base_damping: additional base damping (1 - exp(-base_damping*u)).

  • asymmetry: side gain imbalance in [-1, 1] (+Y vs -Y).

  • lateral_strength: share of ripple applied to local +/-Y (edge outline).

  • vertical_strength: share of ripple applied to local +/-Z (opposite by side).

source
PlantGeom.LaminaMidribMap Type
julia
LaminaMidribMap(curve; up=(0, 0, 1))
LaminaMidribMap(; base_angle_deg=35.0, bend=0.35, tip_drop=0.12,
    side_sway=0.0, weights=(1.0, 0.8, 0.9, 1.0), up=(0, 0, 1))

Point-map for lamina deformation around a midrib centerline. The base reference mesh is expected to use the AMAP convention: leaf length along local +X, width along +Y, thickness along +Z. Coordinates are interpreted in a normalized unit frame (x ∈ [0, 1], |y| ≤ 0.5).

The map bends the blade by wrapping each local point around a midrib curve while preserving lateral width and thickness offsets in the local moving frame.

source
PlantGeom.LaminaTwistRollMap Type
julia
LaminaTwistRollMap(; tip_twist_deg=0.0, roll_strength=0.0, roll_exponent=1.0)

Point map for lamina torsion and cross-blade rolling on a flat leaf mesh following the AMAP axis convention (+X length, +Y width, +Z thickness).

  • tip_twist_deg: progressive twist (rotation around local +X) from base to tip.

  • roll_strength: quadratic edge curl contribution toward local +Z.

  • roll_exponent: progression exponent along the blade (u^roll_exponent).

source
PlantGeom.Material Type

A material for the illumination model (e.g. Phong illumination).

source
PlantGeom.Phong Type

Data structure for a mesh material that is used to describe the light components of a Phong reflection type model. All data is stored as RGBα for Red, Green, Blue and transparency.

source
PlantGeom.PointMapFrame Type
julia
PointMapFrame(map; length=1.0, width=1.0, z_scale=length)
with_point_map_frame(map; length=1.0, width=1.0, z_scale=length)

Apply dimensions before midrib wrapping when using normalized lamina maps.

This wrapper is intended for:

  • LaminaMidribMap

  • ComposedPointMap(..., LaminaMidribMap(...))

Input coordinates are expected in normalized blade space when calling the map directly. When used through PointMappedGeometry, source coordinates are auto-normalized from the reference mesh bounds before this frame map is applied. length scales the midrib centerline, while width and z_scale scale lateral and thickness offsets in the local side/normal frame of the midrib (instead of anisotropic world-axis scaling after deformation).

source
PlantGeom.PointMappedGeometry Type
julia
PointMappedGeometry(ref_mesh, point_map; params=nothing, transformation=IdentityTransformation())

Geometry source that deforms a RefMesh by applying point_map to each local vertex.

Use this for non-affine per-vertex mappings while keeping the classic Geometry path optimized for affine-style instancing. point_map is called as point_map(point, params) when that method exists, otherwise as point_map(point). After the local deformation, the optional transformation is applied.

source
PlantGeom.RationalBezierCurve Type
julia
RationalBezierCurve(control_points, weights=ones(length(control_points)))

Rational Bezier curve in 3D, convenient for point-mapped organs such as cereal leaves whose midrib is easier to describe from a few weighted control points.

control_points are interpreted as 3D positions. weights default to 1 for a standard Bezier curve.

source
PlantGeom.RefMesh Type
julia
RefMesh(
    name::S
    mesh::SimpleMesh
    normals::N
    texture_coords::T
    material::M
    taper::Bool
)

RefMesh(name, mesh, material = RGB(220 / 255, 220 / 255, 220 / 255))

RefMesh type. Stores all information about a Mesh:

  • name::S: the mesh name

  • mesh::SimpleMesh: the actual mesh information -> points and topology

  • normals::Vector{Float64}: the normals, given as a vector of x1,y1,z1,x2,y2,z2...

  • texture_coords::Vector{Float64}: the texture coordinates (not used yet), idem, a vector

  • material::M: the material, used to set the shading

  • taper::Bool: true if tapering is enabled

The reference meshes are then transformed on each node of the MTG using a transformation matrix to match the actual mesh.

source
PlantGeom.SequentialTransformation Type
julia
SequentialTransformation(outer, inner)

Transformation wrapper that preserves sequential application order (outer ∘ inner) without collapsing to a single affine matrix in Float64.

source
PlantGeom.StaticGeometryJob Type
julia
StaticGeometryJob

Typed scene-materialization job for classic RefMesh + transformation geometries.

source
Base.:== Method
julia
==(a::Geometry, b::Geometry)

Test RefMesh equality.

source
Base.:== Method
julia
==(a::RefMesh, b::RefMesh)

Test RefMesh equality.

source
PlantGeom._gwa_scalar_string Method
julia
write_gwa(file, mtg)

Write an MTG object to disk as a GWA mesh file.

source
PlantGeom._normalize_node_symbol Method
julia
merge_children_geometry!(mtg; from, into, delete=:nodes, verbose=true, child_link_fun=x -> new_child_link(x, verbose))

Simplifies the geometry of a MultiScaleTreeGraph (MTG) by merging low-scale geometries into an higher-scale geometry.

Arguments

  • mtg: The MultiScaleTreeGraph to process.

  • from: The symbol for the type of nodes to simplify. Can be a symbol/string or a vector/tuple of those, e.g. [:Petiole, :Rachis].

  • into: The symbol for the type of nodes to merge into. Must be a single symbol/string, e.g. :Leaf.

  • delete: A symbol indicating whether to delete the nodes or the geometry after merging:

    • :none: No deletion will be performed, the geometry is merged into the into nodes, and also kept as before in the from nodes.

    • :nodes: The nodes of type from will be deleted after merging.

    • :geometry: Only the geometry will be deleted, but the from nodes will remain in the MTG.

  • verbose: A boolean indicating if information should be returned when nodes or geometry was not found on expected nodes

  • child_link_fun: A function that takes a parent node targeted for deletion and returns the new links for their children. Required if delete is true. The

default function is new_child_link, which tries to be clever considering the parent and child links. See its help page for more information. If the link shouldn't be modified, use the link function instead.

Returns

  • Nothing. The function modifies the mtg in place.

Notes

If no geometry is found in the children nodes of type from, an informational message is logged.

source
PlantGeom._opf_is_space Method

Parse an array of values from the OPF into a Julia array (Arrays in OPFs are not following XML recommendations)

source
PlantGeom._opf_scalar_string Method
julia
write_opf(file, opf)

Write an MTG with explicit geometry to disk as an OPF file.

source
PlantGeom.align_ref_meshes Method
julia
align_ref_meshes(meshes::Vector{<:RefMesh})

Align all reference meshes along the X axis. Used for visualisation only.

source
PlantGeom.attributes_to_xml Method
julia
attributes_to_xml(node, xml_parent)

Write an MTG node into an XML node.

source
PlantGeom.build_merged_mesh_with_map Method
julia
build_merged_mesh_with_map(mtg; filter_fun=nothing, symbol=nothing, scale=nothing, link=nothing)

Traverse selected MTG nodes and merge their geometry meshes into a single mesh.

Returns a merged mesh and a face2node::Vector{Int} mapping each face index in the merged mesh to the originating MTG node id (MultiScaleTreeGraph.node_id(node)).

source
PlantGeom.build_merged_mesh_with_map_threaded Method
julia
build_merged_mesh_with_map_threaded(mtg; filter_fun=nothing, symbol=nothing, scale=nothing, link=nothing)

Alias to build_merged_mesh_with_map. Threaded implementation removed.

source
PlantGeom.bump_scene_version! Method
julia
bump_scene_version!(mtg; by=1)

Increment the scene version to invalidate any cached merged scene.

source
PlantGeom.calculate_segment_angles Method
julia
calculate_segment_angles(young_modulus, initial_angle, beam_length, tapering, segment_positions;
    length_scale=100.0, integration_steps=10)

Calculate global angles (radians) at each segment boundary position according to the Young's-modulus bending model.

source
PlantGeom.circle_section_profile Function
julia
circle_section_profile(n_sides=8; radius=0.5, close_loop=true)

Create a circular section profile in local section coordinates (XY plane, z=0).

This mirrors AMAPStudio's Mesh.makeCircle(n, radius) helper. When close_loop=true, the first point is repeated at the end.

source
PlantGeom.color_type Method
julia
color_type(color, opf)

Return the type of the color, whether it is an attribute, a colorant, or a RefMeshColorant.

Arguments

  • color: The color to be checked.

  • opf: The MTG to be plotted.

Returns

  • RefMeshColorantType: If color is nothing (the default) to color by reference mesh.

  • DictRefMeshColorantType: If the color is a dictionary mapping reference meshes to colorants.

  • DictVertexRefMeshColorantType: If the color is a dictionary mapping vertices to colorants.

  • VectorColorantType: If the color is a vector of colorants, then we color each mesh by that vector.

  • VectorSymbolType: If the color is a vector of symbols, then we color each mesh by that vector.

  • AttributeColorantType: If the color is an attribute of the MTG, then we color by that attribute.

  • T: If the color is a colorant, then we color everything by that color.

Examples

julia
using MultiScaleTreeGraph, PlantGeom, Colors

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")

opf = read_opf(file)

# Colors:
color_type(:red, opf)
color_type(RGB(0.1,0.5,0.1), opf)

# Attributes:
color_type(:Length, opf)

# Default color:
color_type(nothing, opf)

# Dict of colors:
color_type(Dict(1=>RGB(0.1,0.5,0.1), 2=>RGB(0.5,0.1,0.1)), opf)
source
PlantGeom.colorant_to_string Method
julia
colorant_to_string(x)

Parse a geometry material for OPF writing.

source
PlantGeom.coordinates! Method
julia
coordinates!(mtg; angle = 45; force = false)

Compute dummy 3d coordinates for the mtg nodes using an alterning phyllotaxy. Used when coordinates are missing. Coordinates are just node attributes with reserved names: :XX, :YY and :ZZ.

Returns

Nothing, mutates the mtg in-place (adds :XX, :YY and :ZZ to nodes).

Examples

julia
file = joinpath(dirname(dirname(pathof(MultiScaleTreeGraph))),"test","files","simple_plant.mtg")
mtg = read_mtg(file)
coordinates!(mtg)
to_table(mtg, vars=[:XX, :YY, :ZZ])
source
PlantGeom.default_amap_geometry_convention Method
julia
default_amap_geometry_convention(; angle_unit=:deg)

Return a GeometryConvention close to AMAP/OpenAlea defaults:

  • organ length aligned on the local +X axis

  • insertion angles (XInsertionAngle, YInsertionAngle, ZInsertionAngle)

  • local Euler angles (XEuler, YEuler, ZEuler)

  • OPF-style translations (XX, YY, ZZ) still supported

source
PlantGeom.default_amap_reconstruction_options Method
julia
default_amap_reconstruction_options()

Return AmapReconstructionOptions() with the default AMAP-compatible settings.

Use this when your MTG follows the default AMAP naming/profile and you do not need to customize explicit-coordinate behavior or order-based defaults.

source
PlantGeom.diagram Function
julia
diagram(opf::MultiScaleTreeGraph.Node; kwargs...)
diagram!(opf::MultiScaleTreeGraph.Node; kwargs...)

Make a diagram of the MTG tree using a Makie.jl backend.

Danger

This function is an extension to the package. It is only available if you imported a Makie backend (e.g. using GLMakie) prior to using PlantGeom.

The main attributes are:

  • color: the color of the nodes

  • colormap: the colormap used if the color uses an attribute. By default it uses viridis.

Must be a ColorScheme from ColorSchemes or a Symbol with its name.

Examples

julia
using GLMakie, PlantGeom

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")

opf = read_opf(file)

diagram(opf)

# We can also color the 3d plot with several options:
# With one shared color:
diagram(opf, color = :red)

# Or colouring by opf attribute, *e.g.* using the nodes Z coordinates:
diagram(opf, color = :ZZ)
source
PlantGeom.diagram! Function
julia
diagram(opf::MultiScaleTreeGraph.Node; kwargs...)
diagram!(opf::MultiScaleTreeGraph.Node; kwargs...)

Make a diagram of the MTG tree using a Makie.jl backend.

Danger

This function is an extension to the package. It is only available if you imported a Makie backend (e.g. using GLMakie) prior to using PlantGeom.

The main attributes are:

  • color: the color of the nodes

  • colormap: the colormap used if the color uses an attribute. By default it uses viridis.

Must be a ColorScheme from ColorSchemes or a Symbol with its name.

Examples

julia
using GLMakie, PlantGeom

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")

opf = read_opf(file)

diagram(opf)

# We can also color the 3d plot with several options:
# With one shared color:
diagram(opf, color = :red)

# Or colouring by opf attribute, *e.g.* using the nodes Z coordinates:
diagram(opf, color = :ZZ)
source
PlantGeom.effective_parameters Method
julia
effective_parameters(node, prototype; overrides=NamedTuple())

Resolve prototype parameters for a node with precedence: overrides > node prototype overrides > node attribute aliases > prototype defaults.

source
PlantGeom.extend_pos Method

Add a new point after (x1,y1) using same direction and length relative to it

source
PlantGeom.extrude_profile_mesh Method
julia
extrude_profile_mesh(section, path;
    widths=nothing,
    heights=nothing,
    path_normals=nothing,
    torsion=true,
    close_section=nothing,
    cap_ends=false)

Build a GeometryBasics.Mesh by sweeping a profile section along a 3D path.

This is an AMAP-style extrusion primitive (similar in spirit to AMAPStudio's MeshBuilder.ExtrudeData + ExtrudedMesh):

  • section: profile points in local section coordinates.

  • path: centerline points.

  • widths / heights: per-path scaling of the section local axes.

  • path_normals: optional per-path local normal vectors.

  • torsion: if false, uses a fixed-section normal plane (reprojected along path).

  • close_section: if true, connects last/first section points; if nothing, auto-detect.

  • cap_ends: if true and section is closed, adds start/end caps.

The returned mesh is expressed in local coordinates, ready to be wrapped in RefMesh.

source
PlantGeom.extrude_profile_refmesh Method
julia
extrude_profile_refmesh(name, section, path;
    material=RGB(220 / 255, 220 / 255, 220 / 255),
    cache=nothing,
    widths=nothing,
    heights=nothing,
    path_normals=nothing,
    torsion=true,
    close_section=nothing,
    cap_ends=false)

Create a RefMesh directly from extrude_profile_mesh.

Extrusion options are forwarded to extrude_profile_mesh.

source
PlantGeom.extrude_tube_mesh Method
julia
extrude_tube_mesh(path;
    n_sides=8,
    radius=0.5,
    radii=nothing,
    widths=nothing,
    heights=nothing,
    path_normals=nothing,
    torsion=true,
    cap_ends=false)

Convenience wrapper to extrude a circular section along a path.

  • radius: base circular section radius.

  • radii: per-path isotropic scaling (applied to both width and height).

  • widths / heights: optional anisotropic per-path scaling.

widths/heights take precedence over radii when explicitly provided.

source
PlantGeom.extrusion_make_curve Method
julia
extrusion_make_curve(z_keys, r_keys, n)

AMAP-style radial curve helper (similar to Mesh.makeCurve), used by lathe.

This interpolation preserves local extrema in r_keys by forcing zero slope at intermediate local minima/maxima, then sampling with cubic Hermite interpolation. Returns (z_samples, r_samples) with n + 1 values each.

source
PlantGeom.extrusion_make_interpolation Method
julia
extrusion_make_interpolation(n, key_values)

AMAP-style scalar interpolation helper (similar to Mesh.makeInterpolation).

Returns n + 1 scalar values sampled linearly between key values.

source
PlantGeom.extrusion_make_path Method
julia
extrusion_make_path(n, key_points; key_tangents=nothing)

AMAP-style Hermite path interpolation helper (similar to Mesh.makePath).

Returns n + 1 sampled 3D points passing through the key points. If key_tangents is omitted, tangents are estimated from neighboring keys.

source
PlantGeom.extrusion_make_spline Method
julia
extrusion_make_spline(n, key_points)

AMAP-style spline helper (similar to Mesh.makeSpline) using Catmull-Rom interpolation.

Returns n + 1 sampled 3D points passing near the key points.

source
PlantGeom.final_angle Method
julia
final_angle(young_modulus, z_angle, beam_length, tapering;
    length_scale=100.0, threshold=π / 180.0, max_iter=500)

Calculate the maximal deformation angle of a cantilever beam.

z_angle is the initial angle from vertical (radians). beam_length is scaled by length_scale before evaluation to support legacy formulations expressed in centimeters (length_scale=100.0 when length is provided in meters).

source
PlantGeom.geometry_from_attributes Method
julia
geometry_from_attributes(node, ref_mesh; convention=default_geometry_convention(), dUp=1.0, dDwn=1.0, warn_missing=false)

Create a Geometry from node attributes and a reference mesh.

source
PlantGeom.geometry_to_mesh Method
julia
geometry_to_mesh(geom)

Materialize a geometry object into a concrete mesh.

This is an internal extension point used by scene merging and rendering. Additional geometry sources can provide their own method without changing the rendering API.

source
PlantGeom.get_attr_type Method

Get the attributes types in Julia DataType.

source
PlantGeom.get_cached_scene Method
julia
get_cached_scene(mtg, key) -> Union{Nothing,NamedTuple}

Retrieve the single cached merged scene if it matches key. Returns a NamedTuple with (hash, mesh, face2node) or nothing.

source
PlantGeom.get_color Method
julia
get_color(var <: AbstractArray, range_var, colormap=colorschemes[:viridis])
get_color(var, range_var, colormap=colorschemes[:viridis])

Map value(s) to colors from a colormap based on a range of values

Arguments

  • var: value(s) to map to colors

  • range_var: range of values to map to colors

  • colormap: colormap to use

Returns

  • color: color(s) corresponding to var

Examples

julia
using Colors

get_color(1, 1:2, colormap = colorschemes[:viridis]) # returns RGB{N0f8}(0.267004,0.00487433,0.329415)
get_color(1:2, 1:10, colormap = colorschemes[:viridis]) # returns RGB{N0f8}(0.267004,0.00487433,0.329415)
get_color(1:2, 1:10, 1, colormap = colorschemes[:viridis]) # returns RGB{N0f8}(0.267004,0.00487433,0.329415)
source
PlantGeom.get_color_range Method
julia
get_color_range(colorrange, opf, colorant)

Get the color range from the colorrange argument or from the MTG attribute.

Arguments

  • colorrange: the color range specified by the user, can be an Observable or a tuple of two values.

  • opf: the MTG object.

  • colorant: the color attribute to use for the range.

Returns

  • colorrange: the color range as a tuple of two values.
source
PlantGeom.get_colormap Method
julia
get_colormap(colormap)

Get the colormap as a ColorScheme if it is a named color or ColorScheme

source
PlantGeom.get_mtg_color Method
julia
get_mtg_color(color, opf)

Return the color to be used for the plot.

Arguments

  • color: The color to be checked.

  • opf: The MTG to be plotted.

Returns

The color to be used for the plot.

Examples

julia
using MultiScaleTreeGraph, PlantGeom, Colors
file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
opf = read_opf(file)

get_mtg_color(:red, opf)
get_mtg_color(RGB(0.1,0.5,0.1), opf)
get_mtg_color(:Length, opf)
get_mtg_color(:slategray3, opf)
get_mtg_color(Dict(1=>RGB(0.1,0.5,0.1), 2=>RGB(0.1,0.1,0.5)), opf)
get_mtg_color(Dict(1 => :burlywood4, 2 => :springgreen4), opf)
source
PlantGeom.get_ref_mesh_name Method
julia
get_ref_mesh_name(node)

Get the reference-mesh-like name used by the current node geometry source.

source
PlantGeom.get_ref_meshes Method
julia
get_ref_meshes(mtg)

Get all reference meshes from an mtg, usually from an OPF.

source
PlantGeom.get_ref_meshes_color Method
julia
get_ref_meshes_color(meshes)

Get the reference meshes colors (only the diffuse part for now).

Arguments

  • meshes::Dict{Int, RefMesh}: Dictionary of reference meshes as returned by parse_ref_meshes

  • meshes::AbstractVector{<:RefMesh}: Vector/list of reference meshes (legacy and plotting workflows)

Returns

  • Dict{String, Colorant}: Dictionary mapping mesh names to their diffuse colors

Notes

  • Only the diffuse component of the material is used for the color

  • Dictionary input preserves OPF shape-ID keyed workflows

source
PlantGeom.has_geometry Method
julia
has_geometry(node)

Return true if the node has geometry, false otherwise.

source
PlantGeom.lamina_mesh Function
julia
lamina_mesh(length=1.0, max_width=1.0; n_long=24, n_half=4, width_power=0.85)

Build a flat cereal-like leaf mesh aligned with the AMAP convention: length along local +X, width along +Y, thickness along +Z.

This mesh is intended to be used with PointMappedGeometry, especially with LaminaMidribMap.

source
PlantGeom.lamina_midrib Method
julia
lamina_midrib(; base_angle_deg=35.0, bend=0.35, tip_drop=0.12,
    side_sway=0.0, weights=(1.0, 0.8, 0.9, 1.0))

Build a cereal-like leaf midrib as a weighted cubic Bezier curve.

  • The curve is normalized in a unit frame: length in [0, 1], half-width near 0.5.

  • base_angle_deg: launch angle of the leaf at the sheath.

  • bend: curvature intensity (higher bends more).

  • tip_drop: additional downward displacement at the tip (relative to unit length).

  • side_sway: lateral displacement of the distal blade (relative to unit length).

source
PlantGeom.lamina_refmesh Method
julia
lamina_refmesh(name; length=1.0, max_width=1.0, n_long=24, n_half=4,
    width_power=0.85, material=RGB(0.16, 0.55, 0.22))

Convenience wrapper around lamina_mesh returning a reusable RefMesh.

source
PlantGeom.lathe_gen_mesh Method
julia
lathe_gen_mesh(n_sides, z_coords, radii;
    axis=:x, cap_ends=false)

AMAP-style lathe generator (similar to latheGen): revolve sampled radii around the main axis.

source
PlantGeom.lathe_gen_refmesh Method
julia
lathe_gen_refmesh(name, n_sides, z_coords, radii;
    material=RGB(220 / 255, 220 / 255, 220 / 255),
    cache=nothing,
    axis=:x,
    cap_ends=false)

Create a RefMesh from lathe_gen_mesh.

source
PlantGeom.lathe_mesh Method
julia
lathe_mesh(n_sides, n, z_keys, r_keys;
    method=:curve,
    axis=:x,
    cap_ends=false)

AMAP-style lathe with key profiles (similar to lathe):

  • method=:curve matches AMAP makeCurve behavior (local extrema preserving).

  • method=:spline uses Catmull-Rom interpolation.

  • method=:path uses Hermite interpolation.

source
PlantGeom.lathe_refmesh Method
julia
lathe_refmesh(name, n_sides, n, z_keys, r_keys;
    material=RGB(220 / 255, 220 / 255, 220 / 255),
    cache=nothing,
    method=:curve,
    axis=:x,
    cap_ends=false)

Create a RefMesh from lathe_mesh.

source
PlantGeom.leaflet_midrib_profile Method
julia
leaflet_midrib_profile(; lamina_angle_deg=40.0, scale=0.5)

Return a 3-point open section profile commonly used to mimic a leaflet with a central midrib (AMAP-style V section).

The profile lies in local section coordinates and is typically swept along the organ length axis with extrude_profile_mesh.

source
PlantGeom.local_flexion Method
julia
local_flexion(current_angle, final_angle, young_modulus, tapering, relative_position)

Calculate the local bending angle increment at a relative beam position. Angles are in radians and relative_position is expected in [0, 1].

source
PlantGeom.map_coord Method
julia
map_coord(f, mesh, coord)

Apply function f over the mesh coordinates coord. Values for coord can be 1 for x, 2 for y and 3 for z.

source
PlantGeom.materialBDD_to_material Method

Parse a material in opf format to a Phong material.

source
PlantGeom.material_to_opf_string Method
julia
material_to_opf_string(material::Phong)
material_to_opf_string(material::Colorant)

Format a material into a Dict for OPF writting.

source
PlantGeom.merge_simple_meshes Method
julia
merge_simple_meshes(meshes) -> mesh

Merge a collection of meshes into a single mesh in one pass by concatenating vertices and reindexing faces with running offsets.

source
PlantGeom.meshBDD_to_meshes Method
julia
meshBDD_to_meshes(x)
source
PlantGeom.mtg_coordinates_df Function
julia
mtg_coordinates_df(mtg, attr; force = false)
mtg_coordinates_df!(mtg, attr; force = false)

Extract the coordinates of the nodes of the mtg and the coordinates of their parents (:XX_from, :YY_from, :ZZ_from) and output a DataFrame. Optionally you can also provide an attribute to add to the output DataFrame too by passing its name as a symbol to attr.

The coordinates are computed using coordinates! if missing, or if force = true.

source
PlantGeom.mtg_to_opf_link Method
julia
mtg_to_opf_link(link)
source
PlantGeom.mtg_topology_to_xml! Function
julia
mtg_topology_to_xml!(node, xml_parent)

Write the MTG topology, attributes and geometry into XML format.

source
PlantGeom.nelements Method
julia
nelements(meshes::RefMesh)

Return the number of triangular elements of a reference mesh.

source
PlantGeom.normals_vertex Method
julia
normals_vertex(mesh)

Compute per vertex normals and return them as GeometryBasics.Vec{3,Float64}.

source
PlantGeom.nvertices Method
julia
nvertices(meshes::RefMesh)

Return the number of vertices of a reference mesh.

source
PlantGeom.parse_materialBDD! Method
julia
parse_materialBDD!(node; file=nothing)

Parse the materialBDD section directly from XML child elements.

When the section is present but empty, a neutral default material is inserted so OPF files without explicit materials remain readable.

source
PlantGeom.parse_meshBDD! Method
julia
parse_meshBDD!(node; file="")

Parse the meshBDD section using parse_opf_array.

Supports both flat <faces> arrays and nested <face> elements. Polygon faces with more than three vertices are triangulated with a fan strategy.

source
PlantGeom.parse_opf_attributeBDD! Method

Parse the opf attributes as a Dict.

source
PlantGeom.parse_opf_elements! Method

Generic parser for OPF elements.

Arguments

  • opf::OrderedDict: the opf Dict (using [XMLDict.xml_dict])

  • elem_types::Array: the target types of the element (e.g. "[String, Int64]")

Details

elem_types should be of the same length as the number of elements found in each item of the subchild. elem_types = [Float64, Float64, Float64, Float64, Float64, Float64]

source
PlantGeom.parse_opf_topology! Function
julia
parse_opf_topology!(node, mtg, features, attr_type, mtg_type, ref_meshes, ...)

Parser of the OPF topology.

Arguments

  • node::ElementNode: the XML node to parse.

  • mtg::Union{Nothing,Node}: the parent MTG node.

  • features::Dict: the features of the OPF.

  • attr_type::DataType: the type of the attributes to use.

  • mtg_type::DataType: the type of the MTG to use.

  • ref_meshes::Dict: the reference meshes.

  • read_id::Bool: whether to read the ID from the OPF or recompute it on the fly.

  • max_id::RefValue{Int64}=Ref(1): the ID of the first node, if read_id==false.

  • attributeBDD::Dict{String,String}=Dict{String,String}(): the attributeBDD for dynamic attribute type discovery.

  • attribute_types::Dict{String,DataType}=Dict{String,DataType}(): explicit user type mapping.

  • dynamic_attributes::Set{String}=Set{String}(): names of attributes inferred dynamically.

Note

The transformation matrices in geometry are 3*4.

source
PlantGeom.parse_ref_meshes Method
julia
parse_ref_meshes(opf_attr)

Parse the reference meshes from OPF attributes into a dictionary.

Arguments

  • opf_attr::Dict: Dictionary containing OPF attributes including :meshBDD, :materialBDD, and :shapeBDD

Returns

  • Dict{Int, RefMesh}: A dictionary mapping shape IDs to RefMesh objects

Notes

  • The returned dictionary uses the actual shape IDs from the OPF file as keys

  • This differs from the previous implementation which returned an array with 1-based indexing

  • Shape IDs, mesh indices, and material indices are used as-is from the OPF file (0-based)

source
PlantGeom.plantviz Function
julia
plantviz(mtg::MultiScaleTreeGraph.Node; kwargs...)
plantviz!(mtg::MultiScaleTreeGraph.Node; kwargs...)

Vizualise the 3D geometry of an MTG (usually read from an OPF). This function search for the :geometry attribute in each node of the MTG, and build the vizualisation using the reference meshes and the associated transformation matrix.

Arguments

  • mtg: The MTG to be vizualised.

  • kwargs: Additional arguments to be passed to plantviz!, wich includes:

    • color: The color to be used for the plot. Can be a colorant, an attribute of the MTG (given as a Symbol), or a dictionary of colors for each reference mesh.

    • colormap: The colorscheme to be used for the plot. Can be a Symbol or a ColorScheme.

    • segmentcolor: The color to be used for the facets. Should be a colorant or a symbol of color.

    • showsegments: A boolean indicating whether the facets should be shown or not.

    • color_missing=RGBA(0, 0, 0, 0.3): The color to be used for missing values. Should be a colorant or a symbol of color.

    • index: An integer giving the index of the attribute value to be vizualised. This is useful when the attribute is a vector of values for e.g. each timestep.

    • color_cache_name: The name of the color cache. Should be a string (default to a random string).

    • filter_fun: A function to filter the nodes to be plotted. Should be a function taking a node as argument and returning a boolean.

    • symbol: Plot only nodes with this symbol. Prefer Symbol (or vector/tuple of symbols).

    • scale: Plot only nodes with this scale. Should be an Int or a vector of.

    • link: Plot only nodes with this link. Prefer Symbol (or vector/tuple of symbols).

Examples

julia
using MultiScaleTreeGraph, PlantGeom, GLMakie

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")

mtg = read_opf(file)
plantviz(mtg)

# Then plot it again like before, and it will be faster:
plantviz(mtg)

# We can color the 3d plot with several options:
# With one shared color:
plantviz(mtg, color = :red)
# One color per reference mesh:
plantviz(mtg, color = Dict(1 => :burlywood4, 2 => :springgreen4, 3 => :burlywood4))

# Or just changing the color of some:
plantviz(mtg, color = Dict(1 => :burlywood4))

# Or coloring by mtg attribute, e.g. using the mesh max Z coordinates:
transform!(mtg, zmax => :z_max, ignore_nothing = true)
plantviz(mtg, color = :z_max)

# One color for each vertex of the refmesh 1:
vertex_color = get_color(1:nvertices(get_ref_meshes(mtg))[1], [1,nvertices(get_ref_meshes(mtg))[1]])
plantviz(mtg, color = Dict(1 => vertex_color))

# Or even coloring by the value of the Z coordinates of each vertex:
transform!(
    mtg,
    (x -> [v[3] for v in GeometryBasics.coordinates(refmesh_to_mesh(x))]) => :z_vertex,
    filter_fun=node -> hasproperty(node, :geometry)
)
plantviz(mtg, color = :z, showsegments = true)

f,a,p = plantviz(mtg, color = :z, showsegments = true)
p[:color] = :Length
julia
plantviz!(ref_meshes; kwargs...)

Plot all reference meshes in a single 3d plot using Makie.

Examples

julia
using PlantGeom, GLMakie

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
mtg = read_opf(file)
meshes = get_ref_meshes(mtg)

plantviz(meshes)
# With one shared color:
plantviz(meshes, color = :green)
# One color per reference mesh:
plantviz(meshes, color = Dict(1 => :burlywood4, 2 => :springgreen4, 3 => :burlywood4))
# Or just changing the color of some:
plantviz(meshes, color = Dict(1 => :burlywood4, 3 => :burlywood4))
# One color for each vertex of the refmesh 0:
plantviz(meshes, color = Dict(2 => 1:nvertices(meshes)[2]))
source
PlantGeom.plantviz! Function
julia
viplantviz!(mtg; [options])

Visualize the 3D meshes of an MTG using GeometryBasics and Makie. This function adds the plot to an existing scene with options forwarded to plantviz.

source
PlantGeom.read_opf Method
julia
read_opf(file; attr_type = Dict, mtg_type = MutableNodeMTG, attribute_types = Dict())

Read an OPF file, and returns an MTG.

Arguments

  • file::String: The path to the opf file.

  • attr_type::DataType = Dict: kept for backward compatibility and ignored for MultiScaleTreeGraph >= v0.15 (typed columnar attributes backend is always used).

  • mtg_type = MutableNodeMTG: the type used to hold the mtg encoding for each node (i.e.

link, symbol, index, scale). See details section below.

  • read_id::Bool = true: whether to read the ID from the OPF or recompute it on the fly.

  • max_id::RefValue{Int64}=Ref(1): the ID of the first node, if read_id==false.

  • attribute_types::Dict = Dict(): optional explicit mapping from attribute name (String or Symbol) to Julia type (Int*, Float*, Bool, String). When provided, it overrides attributeBDD.

Each parsed topology node stores its original OPF id in :source_topology_id.

Details

attr_type is ignored with MultiScaleTreeGraph >= v0.15 where the typed columnar backend is always used.

The MultiScaleTreeGraph package provides two types for mtg_type, one immutable (NodeMTG), and one mutable (MutableNodeMTG). If you're planning on modifying the mtg encoding of some of your nodes, you should use MutableNodeMTG, and if you don't want to modify anything, use NodeMTG instead as it should be faster.

Note

See the documentation of the MTG format from the MTG package documentation for further details, e.g. The MTG concept.

Returns

The MTG root node. OPF reference meshes are attached on the root as opf[:ref_meshes]::Dict{Int,RefMesh}, keyed by OPF shape IDs (shapeIndex, typically 0-based).

Examples

julia
using PlantGeom
file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")
opf = read_opf(file)
source
PlantGeom.read_ops Method
julia
read_ops(file; attr_type=Dict{String,Any}, mtg_type=MutableNodeMTG, attribute_types=Dict(), kwargs...)

Reads an OPS file and returns the content as a MultiScaleTreeGraph. Per-object OPS transforms (rotation, scale, inclinationAzimut/inclinationAngle, and pos) are applied to geometry during loading. Geometry nodes preserve their original object-local topology ids in :source_topology_id (from OPF/GWA files), while MTG indices remain unique at scene scope.

Additional keyword arguments are forwarded to read_ops_file, e.g. relaxed=true and assume_scale_column=false for legacy OPS rows where the scale column is missing.

attr_type is kept for backward compatibility and ignored with MultiScaleTreeGraph >= v0.15 (columnar attributes backend).

attribute_types is forwarded to read_opf and can be used to override OPF attribute types by name (CSV-like typing override).

source
PlantGeom.read_ops_file Method
julia
read_ops_file(file; relaxed=false, assume_scale_column=true, opf_scale=1.0, gwa_scale=1.0, require_functional_group=false, default_functional_group="")

Read the content of an .ops file and return a tuple with the scene dimensions and the object table.

Arguments

  • file::String: Path of the .ops file to read.

  • relaxed::Bool=false: If true, parse rows using whitespace separators and accept extra trailing columns in object rows.

  • assume_scale_column::Bool=true: If false, interpret object rows as legacy x y z inclinationAzimut inclinationAngle rotation [ignored...] (missing scale) and inject scale values using opf_scale/gwa_scale.

  • opf_scale::Float64=1.0: Default object scale applied to .opf rows when assume_scale_column=false.

  • gwa_scale::Float64=1.0: Default object scale applied to .gwa rows when assume_scale_column=false.

  • require_functional_group::Bool=false: If true, throw when parsing an object row before any #[Archimed] ... section header.

  • default_functional_group::AbstractString="": Value assigned to functional_group when no #[Archimed] ... header is active.

Returns

The scene dimensions and the object table as a tuple. The scene dimensions are a tuple of two GeometryBasics.Point{3,Float64} with the origin point and opposite point of the scene. The object table is an array of NamedTuple with the following fields:

  • sceneID::Int: Scene ID.

  • plantID::Int: Plant ID.

  • filePath::String: Path to the .opf or .gwa file.

  • pos::GeometryBasics.Point{3,Float64}: Position of the object.

  • scale::Float64: Scale of the object.

  • inclinationAzimut::Float64: Inclination azimut of the object.

  • inclinationAngle::Float64: Inclination angle of the object.

  • rotation::Float64: Rotation of the object.

  • functional_group::String: Functional group of the object.

source
PlantGeom.reconstruct_geometry_from_attributes! Method
julia
reconstruct_geometry_from_attributes!(mtg, prototypes;
    convention=default_amap_geometry_convention(),
    conventions=Dict(),
    offset_aliases=[:Offset, :offset],
    border_offset_aliases=[:BorderInsertionOffset, :border_insertion_offset, :BorderOffset, :border_offset],
    insertion_mode_aliases=[:InsertionMode, :insertion_mode],
    phyllotaxy_aliases=[:Phyllotaxy, :phyllotaxy, :PHYLLOTAXY],
    verticil_mode=:rotation360,
    amap_options=default_amap_reconstruction_options(),
    prototype_selector=nothing,
    prototype_overrides=nothing,
    dUp=1.0,
    dDwn=1.0,
    warn_missing=false,
    root_align=true,
)

Reconstruct node geometries from attribute conventions and MTG topology.

When no explicit translation attributes are found (XX/YY/ZZ by default), placement follows a topological convention close to AMAP:

  • :<: attach to predecessor top

  • :+: attach to bearer at Offset (or bearer length if missing)

  • :+: default insertion mode is BORDER, adding a lateral offset of BorderInsertionOffset (or bearer top width / 2)

  • :/: attach to parent base

If endpoint attributes (EndX/EndY/EndZ aliases) are present, they override angle-derived orientation and Length for that node: base position comes from translation/topology, and orientation+length are inferred from (base -> end).

source
PlantGeom.refmesh_to_mesh Function
julia
refmesh_to_mesh(node)

Compute a node mesh based on its geometry source.

Examples

julia
using PlantGeom
file = joinpath(dirname(dirname(pathof(PlantGeom))), "test", "files", "simple_plant.opf")
opf = read_opf(file)

node = opf[1][1][1]
new_mesh = refmesh_to_mesh(node)
source
PlantGeom.rotate_point Method

Rotate a point (x1,y1) around (x0, y0) with angle.

source
PlantGeom.scene_cache_key Method
julia
scene_cache_key(mtg; symbol=nothing, scale=nothing, link=nothing, filter_fun=nothing) -> UInt

Compute a stable cache key for the current scene rendering request.

source
PlantGeom.scene_version Method
julia
scene_version(mtg) -> Int

Return the scene version counter stored on the MTG root (default 0).

source
PlantGeom.set_cached_scene! Method
julia
set_cached_scene!(mtg, key; mesh, face2node=nothing)

Store a single merged scene cache with associated key hash. Only mesh and face2node are cached.

source
PlantGeom.set_geometry_from_attributes! Method
julia
set_geometry_from_attributes!(node, ref_mesh; convention=default_geometry_convention(), dUp=1.0, dDwn=1.0, warn_missing=false)

Compute and assign node[:geometry] from attribute conventions.

source
PlantGeom.taper Method

Returns a tapered mesh using dDwn and dUp based on the geometry of an input mesh. Tapering a mesh transforms it into a tapered version (i.e. pointy) or enlarged object, e.g. make a cone from a cylinder.

source
PlantGeom.transform_mesh! Method
julia
transform_mesh!(node::Node, transformation)

Add a new transformation to the node geometry transformation field. The transformation is composed with the previous transformation if any.

transformation must be a CoordinateTransformations.Transformation.

source
PlantGeom.transformation_from_attributes Method
julia
transformation_from_attributes(node; convention=default_geometry_convention(), warn_missing=false)

Build a CoordinateTransformations.Transformation from node attributes using a GeometryConvention.

source
PlantGeom.update_segment_angles! Method
julia
update_segment_angles!(
    segment_nodes,
    young_modulus,
    initial_angle,
    beam_length,
    tapering;
    segment_positions=nothing,
    angle_key=:zenithal_angle,
    mode=:absolute,
    degrees=true,
    length_scale=100.0,
    integration_steps=10,
)

Update angle attributes on an ordered chain of segment nodes.

segment_nodes must be ordered from base to tip. By default, mode=:absolute writes the cumulative zenith angle at each segment boundary. With mode=:incremental, written values are local increments between boundaries.

Returns the computed absolute boundary angles in radians.

source
PlantGeom.update_segment_angles! Method
julia
update_segment_angles!(
    organ_node::MultiScaleTreeGraph.Node,
    young_modulus,
    initial_angle,
    beam_length,
    tapering;
    segment_symbol=:LeafletSegment,
    position_key=:segment_boundaries,
    require_positions=false,
    kwargs...,
)

Convenience wrapper for segmented organs stored as consecutive MTG nodes.

It collects descendants matching segment_symbol (base-to-tip traversal order), optionally reads their boundary positions from position_key, and delegates to the vector-based update_segment_angles!.

source
PlantGeom.write_ops Method
julia
write_ops(file, scene_dimensions, object_table)

Write only the scene table (.ops) from explicit scene dimensions and object rows. Alias to write_ops_file.

source
PlantGeom.write_ops Method
julia
write_ops(file, scene; write_objects=true, objects_subdir="objects", preserve_file_paths=false)

Write a scene MTG to an .ops file. By default this writes one object file per scene child (.opf / .gwa) and emits an OPS row pointing to each object.

  • write_objects=true: also write object files next to the .ops file.

  • objects_subdir="objects": target subdirectory for generated object files when preserve_file_paths=false.

  • preserve_file_paths=false: when true, reuse each child filePath (sanitized to remain relative) for emitted object paths.

source
PlantGeom.write_ops_file Method
julia
write_ops_file(file, scene_dimensions, object_table)

Write only the scene table (.ops) from scene dimensions and object rows. This does not write referenced .opf / .gwa object files.

source
PlantGeom.xmax Function
julia
xmax(x)
ymax(x)
zmax(x)

Get the maximum x, y or z coordinates of a mesh or a Node.

source
PlantGeom.xmin Function
julia
xmin(x)
ymin(x)
zmin(x)

Get the minimum x, y or z coordinates of a mesh or a Node.

source
PlantGeom.ymax Function
julia
xmax(x)
ymax(x)
zmax(x)

Get the maximum x, y or z coordinates of a mesh or a Node.

source
PlantGeom.ymin Function
julia
xmin(x)
ymin(x)
zmin(x)

Get the minimum x, y or z coordinates of a mesh or a Node.

source
PlantGeom.zmax Function
julia
xmax(x)
ymax(x)
zmax(x)

Get the maximum x, y or z coordinates of a mesh or a Node.

source
PlantGeom.zmin Function
julia
xmin(x)
ymin(x)
zmin(x)

Get the minimum x, y or z coordinates of a mesh or a Node.

source
RecipesBase.plot Function
julia
plot(opf::MultiScaleTreeGraph.Node; kwargs...)
plot!(opf::MultiScaleTreeGraph.Node; kwargs...)

Make a diagram of the MTG tree, paired with a Plots.jl backend.

See also diagram for the same plot with a Makie.jl backend.

Attributes

  • mode = "2d": The mode for plotting, either "2d" or "3d"

  • node_color = :black: the node color, can be a color or any MTG attribute

  • edge_color = node_color: same as node_color, but for the edges

  • colormap = :viridis: the colormap used for coloring

  • color_missing = RGBA(0, 0, 0, 0.3): The color used for missing values

Examples

julia
# import Pkg; Pkg.add("PlotlyJS")
using Plots, PlantGeom
plotlyjs()

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")

opf = read_opf(file)

plot(opf, node_color = :Length)
source
RecipesBase.plot! Function
julia
plot(opf::MultiScaleTreeGraph.Node; kwargs...)
plot!(opf::MultiScaleTreeGraph.Node; kwargs...)

Make a diagram of the MTG tree, paired with a Plots.jl backend.

See also diagram for the same plot with a Makie.jl backend.

Attributes

  • mode = "2d": The mode for plotting, either "2d" or "3d"

  • node_color = :black: the node color, can be a color or any MTG attribute

  • edge_color = node_color: same as node_color, but for the edges

  • colormap = :viridis: the colormap used for coloring

  • color_missing = RGBA(0, 0, 0, 0.3): The color used for missing values

Examples

julia
# import Pkg; Pkg.add("PlotlyJS")
using Plots, PlantGeom
plotlyjs()

file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","simple_plant.opf")
# file = joinpath(dirname(dirname(pathof(PlantGeom))),"test","files","coffee.opf")

opf = read_opf(file)

plot(opf, node_color = :Length)
source