0.1.8
Loading...
Searching...
No Matches
pyhelios.PlantArchitecture.PlantArchitecture Class Reference

High-level interface for plant architecture modeling and procedural plant generation. More...

Detailed Description

High-level interface for plant architecture modeling and procedural plant generation.

PlantArchitecture provides access to the comprehensive plant library with 25+ plant models including trees (almond, apple, olive, walnut), crops (bean, cowpea, maize, rice, soybean), and other plants. This class enables procedural plant generation, time-based growth simulation, and plant community modeling.

This class requires the native Helios library built with PlantArchitecture support. Use context managers for proper resource cleanup.

Examples

>>> with Context() as context:
... with PlantArchitecture(context) as plantarch:
... plantarch.loadPlantModelFromLibrary("bean")
... plant_id = plantarch.buildPlantInstanceFromLibrary(base_position=vec3(0, 0, 0), age=30)
... plantarch.advanceTime(10.0) # Grow for 10 days

Definition at line 189 of file PlantArchitecture.py.

Public Member Functions

 __init__ (self, Context context)
 Initialize PlantArchitecture with a Helios context.
 
 __enter__ (self)
 Context manager entry.
 
 __exit__ (self, exc_type, exc_val, exc_tb)
 Context manager exit - cleanup resources.
 
None loadPlantModelFromLibrary (self, str plant_label)
 Load a plant model from the built-in library.
 
int buildPlantInstanceFromLibrary (self, vec3 base_position, float age)
 Build a plant instance from the currently loaded library model.
 
List[int] buildPlantCanopyFromLibrary (self, vec3 canopy_center, vec2 plant_spacing, int2 plant_count, float age)
 Build a canopy of regularly spaced plants from the currently loaded library model.
 
None advanceTime (self, float dt)
 Advance time for plant growth and development.
 
List[str] getAvailablePlantModels (self)
 Get list of all available plant models in the library.
 
List[int] getAllPlantObjectIDs (self, int plant_id)
 Get all object IDs for a specific plant.
 
List[int] getAllPlantUUIDs (self, int plant_id)
 Get all primitive UUIDs for a specific plant.
 
None enableSoftCollisionAvoidance (self, Optional[List[int]] target_object_UUIDs=None, Optional[List[int]] target_object_IDs=None, bool enable_petiole_collision=False, bool enable_fruit_collision=False)
 Enable soft collision avoidance for procedural plant growth.
 
None disableCollisionDetection (self)
 Disable collision detection for plant growth.
 
None setSoftCollisionAvoidanceParameters (self, float view_half_angle_deg=80.0, float look_ahead_distance=0.1, int sample_count=256, float inertia_weight=0.4)
 Configure parameters for soft collision avoidance algorithm.
 
None setCollisionRelevantOrgans (self, bool include_internodes=False, bool include_leaves=True, bool include_petioles=False, bool include_flowers=False, bool include_fruit=False)
 Specify which plant organs participate in collision detection.
 
None enableSolidObstacleAvoidance (self, List[int] obstacle_UUIDs, float avoidance_distance=0.5, bool enable_fruit_adjustment=False, bool enable_obstacle_pruning=False)
 Enable hard obstacle avoidance for specified geometry.
 
None setStaticObstacles (self, List[int] target_UUIDs)
 Mark geometry as static obstacles for collision detection optimization.
 
List[int] getPlantCollisionRelevantObjectIDs (self, int plant_id)
 Get object IDs of collision-relevant geometry for a specific plant.
 
None writePlantMeshVertices (self, int plant_id, Union[str, Path] filename)
 Write all plant mesh vertices to file for external processing.
 
None writePlantStructureXML (self, int plant_id, Union[str, Path] filename)
 Save plant structure to XML file for later loading.
 
None writeQSMCylinderFile (self, int plant_id, Union[str, Path] filename)
 Export plant structure in TreeQSM cylinder format.
 
List[int] readPlantStructureXML (self, Union[str, Path] filename, bool quiet=False)
 Load plant structure from XML file.
 
int addPlantInstance (self, vec3 base_position, float current_age)
 Create an empty plant instance for custom plant building.
 
None deletePlantInstance (self, int plant_id)
 Delete a plant instance and all associated geometry.
 
int addBaseStemShoot (self, int plant_id, int current_node_number, AxisRotation base_rotation, float internode_radius, float internode_length_max, float internode_length_scale_factor_fraction, float leaf_scale_factor_fraction, float radius_taper, str shoot_type_label)
 Add a base stem shoot to a plant instance (main trunk/stem).
 
int appendShoot (self, int plant_id, int parent_shoot_id, int current_node_number, AxisRotation base_rotation, float internode_radius, float internode_length_max, float internode_length_scale_factor_fraction, float leaf_scale_factor_fraction, float radius_taper, str shoot_type_label)
 Append a shoot to the end of an existing shoot.
 
int addChildShoot (self, int plant_id, int parent_shoot_id, int parent_node_index, int current_node_number, AxisRotation shoot_base_rotation, float internode_radius, float internode_length_max, float internode_length_scale_factor_fraction, float leaf_scale_factor_fraction, float radius_taper, str shoot_type_label, int petiole_index=0)
 Add a child shoot at an axillary bud position on a parent shoot.
 
bool is_available (self)
 Check if PlantArchitecture is available in current build.
 

Public Attributes

 context = context
 

Protected Attributes

 _plantarch_ptr = None
 

Constructor & Destructor Documentation

◆ __init__()

pyhelios.PlantArchitecture.PlantArchitecture.__init__ ( self,
Context context )

Initialize PlantArchitecture with a Helios context.

Parameters
contextActive Helios Context instance
Exceptions
PlantArchitectureErrorIf plugin not available in current build
RuntimeErrorIf plugin initialization fails

Definition at line 201 of file PlantArchitecture.py.

Member Function Documentation

◆ __enter__()

pyhelios.PlantArchitecture.PlantArchitecture.__enter__ ( self)

Context manager entry.

Definition at line 230 of file PlantArchitecture.py.

◆ __exit__()

pyhelios.PlantArchitecture.PlantArchitecture.__exit__ ( self,
exc_type,
exc_val,
exc_tb )

Context manager exit - cleanup resources.

Definition at line 234 of file PlantArchitecture.py.

◆ addBaseStemShoot()

int pyhelios.PlantArchitecture.PlantArchitecture.addBaseStemShoot ( self,
int plant_id,
int current_node_number,
AxisRotation base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
float radius_taper,
str shoot_type_label )

Add a base stem shoot to a plant instance (main trunk/stem).

   This method creates the primary shoot originating from the plant base. The base stem
   is typically the main trunk or primary stem from which all other shoots branch.
   Specify growth parameters to control the shoot's morphology and development.

   **IMPORTANT - Shoot Type Requirement**: Shoot types must be defined before use. The standard
   workflow is to load a plant model first using loadPlantModelFromLibrary(), which defines
   shoot types that can then be used for custom building. The shoot_type_label must match a
   shoot type defined in the loaded model.
Parameters
plant_idID of the plant instance
current_node_numberStarting node number for this shoot (typically 1)
base_rotationOrientation as AxisRotation(pitch, yaw, roll) in degrees
internode_radiusBase radius of internodes in meters (must be > 0)
internode_length_maxMaximum internode length in meters (must be > 0)
internode_length_scale_factor_fractionScale factor for internode length (0-1 typically)
leaf_scale_factor_fractionScale factor for leaf size (0-1 typically)
radius_taperRate of radius decrease along shoot (0-1, where 1=no taper)
shoot_type_labelLabel identifying shoot type - must match a type from loaded model
Returns
Shoot ID for the created shoot
Exceptions
ValueErrorIf parameters are invalid (negative IDs, non-positive dimensions, empty label)
PlantArchitectureErrorIf shoot creation fails or shoot type doesn't exist

Examples

>>> from pyhelios import AxisRotation
>>>
>>> # REQUIRED: Load a plant model to define shoot types
>>> plantarch.loadPlantModelFromLibrary("bean")
>>>
>>> # Create empty plant for custom building
>>> plant_id = plantarch.addPlantInstance(vec3(0, 0, 0), 0.0)
>>>
>>> # Add base stem using shoot type from loaded model
>>> shoot_id = plantarch.addBaseStemShoot(
... plant_id=plant_id,
... current_node_number=1,
... base_rotation=AxisRotation(0, 0, 0), # Upright
... internode_radius=0.01, # 1cm radius
... internode_length_max=0.1, # 10cm max length
... internode_length_scale_factor_fraction=1.0,
... leaf_scale_factor_fraction=1.0,
... radius_taper=0.9, # Gradual taper
... shoot_type_label="stem" # Must match loaded model
... )

Definition at line 1131 of file PlantArchitecture.py.

◆ addChildShoot()

int pyhelios.PlantArchitecture.PlantArchitecture.addChildShoot ( self,
int plant_id,
int parent_shoot_id,
int parent_node_index,
int current_node_number,
AxisRotation shoot_base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
float radius_taper,
str shoot_type_label,
int petiole_index = 0 )

Add a child shoot at an axillary bud position on a parent shoot.

   This method creates a lateral branch shoot emerging from a specific node on the
   parent shoot. Child shoots enable creation of branching architectures, with control
   over branch angle, size, and which petiole position the branch emerges from (for
   plants with multiple petioles per node).

   **IMPORTANT - Shoot Type Requirement**: The shoot_type_label must match a shoot type
   defined in a loaded plant model. Load a model with loadPlantModelFromLibrary() before
   calling this method.
Parameters
plant_idID of the plant instance
parent_shoot_idID of the parent shoot
parent_node_indexIndex of the parent node where child emerges (0-based)
current_node_numberStarting node number for this child shoot
shoot_base_rotationOrientation as AxisRotation(pitch, yaw, roll) in degrees
internode_radiusBase radius of child shoot internodes in meters (must be > 0)
internode_length_maxMaximum internode length in meters (must be > 0)
internode_length_scale_factor_fractionScale factor for internode length (0-1 typically)
leaf_scale_factor_fractionScale factor for leaf size (0-1 typically)
radius_taperRate of radius decrease along shoot (0-1, where 1=no taper)
shoot_type_labelLabel identifying shoot type - must match loaded model
petiole_indexWhich petiole at the node to branch from (default: 0)
Returns
Shoot ID for the created child shoot
Exceptions
ValueErrorIf parameters are invalid (negative values, non-positive dimensions, empty label)
PlantArchitectureErrorIf child shoot creation fails, parent doesn't exist, or shoot type not defined

Examples

>>> # Load model to define shoot types
>>> plantarch.loadPlantModelFromLibrary("bean")
>>>
>>> # Add lateral branch at 45-degree angle from node 3
>>> branch_id = plantarch.addChildShoot(
... plant_id=plant_id,
... parent_shoot_id=main_shoot_id,
... parent_node_index=3,
... current_node_number=1,
... shoot_base_rotation=AxisRotation(45, 90, 0), # 45° out, 90° rotation
... internode_radius=0.005, # Thinner than main stem
... internode_length_max=0.06, # Shorter internodes
... internode_length_scale_factor_fraction=1.0,
... leaf_scale_factor_fraction=0.9,
... radius_taper=0.8,
... shoot_type_label="stem"
... )
>>>
>>> # Add second branch from opposite petiole
>>> branch_id2 = plantarch.addChildShoot(
... plant_id, main_shoot_id, 3, 1, AxisRotation(45, 270, 0),
... 0.005, 0.06, 1.0, 0.9, 0.8, "stem", petiole_index=1
... )

Definition at line 1330 of file PlantArchitecture.py.

◆ addPlantInstance()

int pyhelios.PlantArchitecture.PlantArchitecture.addPlantInstance ( self,
vec3 base_position,
float current_age )

Create an empty plant instance for custom plant building.

   This method creates a new plant instance at the specified location without any
   shoots or organs. Use addBaseStemShoot(), appendShoot(), and addChildShoot() to
   manually construct the plant structure. This provides low-level control over
   plant architecture, enabling custom morphologies not available in the plant library.
Parameters
base_positionCartesian (x,y,z) coordinates of plant base as vec3
current_ageCurrent age of the plant in days (must be >= 0)
Returns
Plant ID for the created plant instance
Exceptions
ValueErrorIf age is negative
PlantArchitectureErrorIf plant creation fails

Examples

>>> # Create empty plant at origin
>>> plant_id = plantarch.addPlantInstance(vec3(0, 0, 0), 0.0)
>>>
>>> # Now add shoots to build custom plant structure
>>> shoot_id = plantarch.addBaseStemShoot(
... plant_id, 1, AxisRotation(0, 0, 0), 0.01, 0.1, 1.0, 1.0, 0.8, "mainstem"
... )

Definition at line 1027 of file PlantArchitecture.py.

◆ advanceTime()

None pyhelios.PlantArchitecture.PlantArchitecture.advanceTime ( self,
float dt )

Advance time for plant growth and development.

   This method updates all plants in the simulation, potentially adding new phytomers,
   growing existing organs, transitioning phenological stages, and updating plant geometry.
Parameters
dtTime step to advance in days (must be >= 0)
Exceptions
ValueErrorIf dt is negative
PlantArchitectureErrorIf time advancement fails
Note
Large time steps are more efficient than many small steps. The timestep value can be larger than the phyllochron, allowing multiple phytomers to be produced in a single call.

Examples

>>> plantarch.advanceTime(10.0) # Advance 10 days
>>> plantarch.advanceTime(0.5) # Advance 12 hours

Definition at line 386 of file PlantArchitecture.py.

◆ appendShoot()

int pyhelios.PlantArchitecture.PlantArchitecture.appendShoot ( self,
int plant_id,
int parent_shoot_id,
int current_node_number,
AxisRotation base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
float radius_taper,
str shoot_type_label )

Append a shoot to the end of an existing shoot.

   This method extends an existing shoot by appending a new shoot at its terminal bud.
   Useful for creating multi-segmented shoots with varying properties along their length,
   such as shoots with different growth phases or developmental stages.

   **IMPORTANT - Shoot Type Requirement**: The shoot_type_label must match a shoot type
   defined in a loaded plant model. Load a model with loadPlantModelFromLibrary() before
   calling this method.
Parameters
plant_idID of the plant instance
parent_shoot_idID of the parent shoot to extend
current_node_numberStarting node number for this shoot
base_rotationOrientation as AxisRotation(pitch, yaw, roll) in degrees
internode_radiusBase radius of internodes in meters (must be > 0)
internode_length_maxMaximum internode length in meters (must be > 0)
internode_length_scale_factor_fractionScale factor for internode length (0-1 typically)
leaf_scale_factor_fractionScale factor for leaf size (0-1 typically)
radius_taperRate of radius decrease along shoot (0-1, where 1=no taper)
shoot_type_labelLabel identifying shoot type - must match loaded model
Returns
Shoot ID for the appended shoot
Exceptions
ValueErrorIf parameters are invalid (negative IDs, non-positive dimensions, empty label)
PlantArchitectureErrorIf shoot appending fails, parent doesn't exist, or shoot type not defined

Examples

>>> # Load model to define shoot types
>>> plantarch.loadPlantModelFromLibrary("bean")
>>>
>>> # Append shoot with reduced size to simulate apical growth
>>> new_shoot_id = plantarch.appendShoot(
... plant_id=plant_id,
... parent_shoot_id=base_shoot_id,
... current_node_number=10,
... base_rotation=AxisRotation(0, 0, 0),
... internode_radius=0.008, # Smaller than base
... internode_length_max=0.08, # Shorter internodes
... internode_length_scale_factor_fraction=1.0,
... leaf_scale_factor_fraction=0.8, # Smaller leaves
... radius_taper=0.85,
... shoot_type_label="stem"
... )

Definition at line 1224 of file PlantArchitecture.py.

◆ buildPlantCanopyFromLibrary()

List[int] pyhelios.PlantArchitecture.PlantArchitecture.buildPlantCanopyFromLibrary ( self,
vec3 canopy_center,
vec2 plant_spacing,
int2 plant_count,
float age )

Build a canopy of regularly spaced plants from the currently loaded library model.

Parameters
canopy_centerCartesian (x,y,z) coordinates of canopy center as vec3
plant_spacingSpacing between plants in x- and y-directions (meters) as vec2
plant_countNumber of plants in x- and y-directions as int2
ageAge of all plants in days (must be >= 0)
Returns
List of plant IDs for the created plant instances
Exceptions
ValueErrorIf age is negative or plant count values are not positive
PlantArchitectureErrorIf canopy building fails

Examples

>>> # 3x3 canopy with 0.5m spacing, 30-day-old plants
>>> plant_ids = plantarch.buildPlantCanopyFromLibrary(
... canopy_center=vec3(0, 0, 0),
... plant_spacing=vec2(0.5, 0.5),
... plant_count=int2(3, 3),
... age=30.0
... )

Definition at line 338 of file PlantArchitecture.py.

◆ buildPlantInstanceFromLibrary()

int pyhelios.PlantArchitecture.PlantArchitecture.buildPlantInstanceFromLibrary ( self,
vec3 base_position,
float age )

Build a plant instance from the currently loaded library model.

Parameters
base_positionCartesian (x,y,z) coordinates of plant base as vec3
ageAge of the plant in days (must be >= 0)
Returns
Plant ID for the created plant instance
Exceptions
ValueErrorIf age is negative
PlantArchitectureErrorIf plant building fails
RuntimeErrorIf no model has been loaded

Examples

>>> plant_id = plantarch.buildPlantInstanceFromLibrary(base_position=vec3(2.0, 3.0, 0.0), age=45.0)
>>> plant_id = plantarch.buildPlantInstanceFromLibrary(base_position=vec3(0, 0, 0), age=30.0)

Definition at line 295 of file PlantArchitecture.py.

◆ deletePlantInstance()

None pyhelios.PlantArchitecture.PlantArchitecture.deletePlantInstance ( self,
int plant_id )

Delete a plant instance and all associated geometry.

   This method removes a plant from the simulation, deleting all shoots, organs,
   and associated primitives from the context. The plant ID becomes invalid after
   deletion and should not be used in subsequent operations.
Parameters
plant_idID of the plant instance to delete
Exceptions
ValueErrorIf plant_id is negative
PlantArchitectureErrorIf plant deletion fails or plant doesn't exist

Examples

>>> # Delete a plant
>>> plantarch.deletePlantInstance(plant_id)
>>>
>>> # Delete multiple plants
>>> for pid in plant_ids_to_remove:
... plantarch.deletePlantInstance(pid)

Definition at line 1067 of file PlantArchitecture.py.

◆ disableCollisionDetection()

None pyhelios.PlantArchitecture.PlantArchitecture.disableCollisionDetection ( self)

Disable collision detection for plant growth.

   This method turns off the collision detection system, allowing plants to grow
   without checking for obstacles. This improves performance but plants may grow
   through obstacles and other geometry.
Exceptions
PlantArchitectureErrorIf disabling fails

Examples

>>> plantarch.disableCollisionDetection()

Definition at line 546 of file PlantArchitecture.py.

◆ enableSoftCollisionAvoidance()

None pyhelios.PlantArchitecture.PlantArchitecture.enableSoftCollisionAvoidance ( self,
Optional[List[int]] target_object_UUIDs = None,
Optional[List[int]] target_object_IDs = None,
bool enable_petiole_collision = False,
bool enable_fruit_collision = False )

Enable soft collision avoidance for procedural plant growth.

   This method enables the collision detection system that guides plant growth away from
   obstacles and other plants. The system uses cone-based gap detection to find optimal
   growth directions that minimize collisions while maintaining natural plant architecture.
Parameters
target_object_UUIDsList of primitive UUIDs to avoid collisions with. If empty, avoids all geometry in the context.
target_object_IDsList of compound object IDs to avoid collisions with.
enable_petiole_collisionEnable collision detection for leaf petioles
enable_fruit_collisionEnable collision detection for fruit organs
Exceptions
PlantArchitectureErrorIf collision detection activation fails
Note
Collision detection adds computational overhead. Use setStaticObstacles() to mark static geometry for BVH optimization and improved performance.

Examples

>>> # Avoid all geometry
>>> plantarch.enableSoftCollisionAvoidance()
>>>
>>> # Avoid specific obstacles
>>> obstacle_uuids = context.getAllUUIDs()
>>> plantarch.enableSoftCollisionAvoidance(target_object_UUIDs=obstacle_uuids)
>>>
>>> # Enable collision detection for petioles and fruit
>>> plantarch.enableSoftCollisionAvoidance(
... enable_petiole_collision=True,
... enable_fruit_collision=True
... )

Definition at line 514 of file PlantArchitecture.py.

◆ enableSolidObstacleAvoidance()

None pyhelios.PlantArchitecture.PlantArchitecture.enableSolidObstacleAvoidance ( self,
List[int] obstacle_UUIDs,
float avoidance_distance = 0.5,
bool enable_fruit_adjustment = False,
bool enable_obstacle_pruning = False )

Enable hard obstacle avoidance for specified geometry.

   This method configures solid obstacles that plants cannot grow through. Unlike soft
   collision avoidance (which guides growth), solid obstacles cause complete growth
   termination when encountered within the avoidance distance.
Parameters
obstacle_UUIDsList of primitive UUIDs representing solid obstacles
avoidance_distanceMinimum distance to maintain from obstacles (meters). Growth stops if obstacles are closer. Default 0.5m.
enable_fruit_adjustmentAdjust fruit positions away from obstacles
enable_obstacle_pruningRemove plant organs that penetrate obstacles
Exceptions
ValueErrorIf obstacle_UUIDs is empty or avoidance_distance is non-positive
PlantArchitectureErrorIf solid obstacle configuration fails

Examples

>>> # Simple solid obstacle avoidance
>>> wall_uuids = [1, 2, 3, 4] # UUIDs of wall primitives
>>> plantarch.enableSolidObstacleAvoidance(wall_uuids)
>>>
>>> # Close avoidance with fruit adjustment
>>> plantarch.enableSolidObstacleAvoidance(
... obstacle_UUIDs=wall_uuids,
... avoidance_distance=0.1,
... enable_fruit_adjustment=True
... )

Definition at line 697 of file PlantArchitecture.py.

◆ getAllPlantObjectIDs()

List[int] pyhelios.PlantArchitecture.PlantArchitecture.getAllPlantObjectIDs ( self,
int plant_id )

Get all object IDs for a specific plant.

Parameters
plant_idID of the plant instance
Returns
List of object IDs comprising the plant
Exceptions
ValueErrorIf plant_id is negative
PlantArchitectureErrorIf retrieval fails

Examples

>>> object_ids = plantarch.getAllPlantObjectIDs(plant_id)
>>> print(f"Plant has {len(object_ids)} objects")

Definition at line 439 of file PlantArchitecture.py.

◆ getAllPlantUUIDs()

List[int] pyhelios.PlantArchitecture.PlantArchitecture.getAllPlantUUIDs ( self,
int plant_id )

Get all primitive UUIDs for a specific plant.

Parameters
plant_idID of the plant instance
Returns
List of primitive UUIDs comprising the plant
Exceptions
ValueErrorIf plant_id is negative
PlantArchitectureErrorIf retrieval fails

Examples

>>> uuids = plantarch.getAllPlantUUIDs(plant_id)
>>> print(f"Plant has {len(uuids)} primitives")

Definition at line 467 of file PlantArchitecture.py.

◆ getAvailablePlantModels()

List[str] pyhelios.PlantArchitecture.PlantArchitecture.getAvailablePlantModels ( self)

Get list of all available plant models in the library.

Returns
List of plant model names available for loading
Exceptions
PlantArchitectureErrorIf retrieval fails

Examples

>>> models = plantarch.getAvailablePlantModels()
>>> print(f"Available models: {', '.join(models)}")

Available models: almond, apple, bean, cowpea, maize, rice, soybean, tomato, wheat, ...

Definition at line 413 of file PlantArchitecture.py.

◆ getPlantCollisionRelevantObjectIDs()

List[int] pyhelios.PlantArchitecture.PlantArchitecture.getPlantCollisionRelevantObjectIDs ( self,
int plant_id )

Get object IDs of collision-relevant geometry for a specific plant.

   This method returns the subset of plant geometry that participates in collision
   detection, as filtered by setCollisionRelevantOrgans(). Useful for visualization
   and debugging collision detection behavior.
Parameters
plant_idID of the plant instance
Returns
List of object IDs for collision-relevant plant geometry
Exceptions
ValueErrorIf plant_id is negative
PlantArchitectureErrorIf retrieval fails

Examples

>>> # Get collision-relevant geometry
>>> collision_obj_ids = plantarch.getPlantCollisionRelevantObjectIDs(plant_id)
>>> print(f"Plant has {len(collision_obj_ids)} collision-relevant objects")
>>>
>>> # Highlight collision geometry in visualization
>>> for obj_id in collision_obj_ids:
... context.setObjectColor(obj_id, RGBcolor(1, 0, 0)) # Red

Definition at line 785 of file PlantArchitecture.py.

◆ is_available()

bool pyhelios.PlantArchitecture.PlantArchitecture.is_available ( self)

Check if PlantArchitecture is available in current build.

Returns
True if plugin is available, False otherwise

Definition at line 1389 of file PlantArchitecture.py.

◆ loadPlantModelFromLibrary()

None pyhelios.PlantArchitecture.PlantArchitecture.loadPlantModelFromLibrary ( self,
str plant_label )

Load a plant model from the built-in library.

Parameters
plant_labelPlant model identifier from library. Available models include:
"almond", "apple", "bean", "bindweed", "butterlettuce", "capsicum",
"cheeseweed", "cowpea", "easternredbud", "grapevine_VSP", "maize",
"olive", "pistachio", "puncturevine", "rice", "sorghum", "soybean",
"strawberry", "sugarbeet", "tomato", "cherrytomato", "walnut", "wheat"
Exceptions
ValueErrorIf plant_label is empty or invalid
PlantArchitectureErrorIf model loading fails

Examples

>>> plantarch.loadPlantModelFromLibrary("bean")
>>> plantarch.loadPlantModelFromLibrary("almond")

Definition at line 261 of file PlantArchitecture.py.

◆ readPlantStructureXML()

List[int] pyhelios.PlantArchitecture.PlantArchitecture.readPlantStructureXML ( self,
Union[str, Path] filename,
bool quiet = False )

Load plant structure from XML file.

   This method reads plant architecture data from an XML file previously saved with
   writePlantStructureXML(). The loaded plants are added to the current context
   and can be grown, modified, or analyzed like any other plants.
Parameters
filenamePath to XML file to load (absolute or relative to current working directory)
quietIf True, suppress console output during loading (default: False)
Returns
List of plant IDs for the loaded plant instances
Exceptions
ValueErrorIf filename is empty
PlantArchitectureErrorIf file doesn't exist, cannot be parsed, or loading fails
Note
The XML file can contain multiple plant instances. All plants in the file will be loaded and their IDs returned in a list. Plant models referenced in the XML must be available in the plant library.

Examples

>>> # Load previously saved plants
>>> plant_ids = plantarch.readPlantStructureXML("saved_canopy.xml")
>>> print(f"Loaded {len(plant_ids)} plants")
>>>
>>> # Continue growing the loaded plants
>>> plantarch.advanceTime(10.0)
>>>
>>> # Load quietly without console messages
>>> plant_ids = plantarch.readPlantStructureXML("bean_day45.xml", quiet=True)

Definition at line 981 of file PlantArchitecture.py.

◆ setCollisionRelevantOrgans()

None pyhelios.PlantArchitecture.PlantArchitecture.setCollisionRelevantOrgans ( self,
bool include_internodes = False,
bool include_leaves = True,
bool include_petioles = False,
bool include_flowers = False,
bool include_fruit = False )

Specify which plant organs participate in collision detection.

   This method allows filtering which organs are considered during collision detection,
   enabling optimization by excluding organs unlikely to cause problematic collisions.
Parameters
include_internodesInclude stem internodes in collision detection
include_leavesInclude leaf blades in collision detection
include_petiolesInclude leaf petioles in collision detection
include_flowersInclude flowers in collision detection
include_fruitInclude fruit in collision detection
Exceptions
PlantArchitectureErrorIf organ filtering fails

Examples

>>> # Only detect collisions for stems and leaves (default behavior)
>>> plantarch.setCollisionRelevantOrgans(
... include_internodes=True,
... include_leaves=True
... )
>>>
>>> # Include all organs
>>> plantarch.setCollisionRelevantOrgans(
... include_internodes=True,
... include_leaves=True,
... include_petioles=True,
... include_flowers=True,
... include_fruit=True
... )

Definition at line 647 of file PlantArchitecture.py.

◆ setSoftCollisionAvoidanceParameters()

None pyhelios.PlantArchitecture.PlantArchitecture.setSoftCollisionAvoidanceParameters ( self,
float view_half_angle_deg = 80.0,
float look_ahead_distance = 0.1,
int sample_count = 256,
float inertia_weight = 0.4 )

Configure parameters for soft collision avoidance algorithm.

   These parameters control the cone-based gap detection algorithm that guides
   plant growth away from obstacles. Adjusting these values allows fine-tuning
   the balance between collision avoidance and natural growth patterns.
Parameters
view_half_angle_degHalf-angle of detection cone in degrees (0-180). Default 80° provides wide field of view.
look_ahead_distanceDistance to look ahead for collisions in meters. Larger values detect distant obstacles. Default 0.1m.
sample_countNumber of ray samples within cone. More samples improve accuracy but reduce performance. Default 256.
inertia_weightWeight for previous growth direction (0-1). Higher values make growth smoother but less responsive. Default 0.4.
Exceptions
ValueErrorIf parameters are outside valid ranges
PlantArchitectureErrorIf parameter setting fails

Examples

>>> # Use default parameters (recommended)
>>> plantarch.setSoftCollisionAvoidanceParameters()
>>>
>>> # Tune for dense canopy with close obstacles
>>> plantarch.setSoftCollisionAvoidanceParameters(
... view_half_angle_deg=60.0, # Narrower detection cone
... look_ahead_distance=0.05, # Shorter look-ahead
... sample_count=512, # More accurate detection
... inertia_weight=0.3 # More responsive to obstacles
... )

Definition at line 587 of file PlantArchitecture.py.

◆ setStaticObstacles()

None pyhelios.PlantArchitecture.PlantArchitecture.setStaticObstacles ( self,
List[int] target_UUIDs )

Mark geometry as static obstacles for collision detection optimization.

   This method tells the collision detection system that certain geometry will not
   move during the simulation. The system can then build an optimized Bounding Volume
   Hierarchy (BVH) for these obstacles, significantly improving collision detection
   performance in scenes with many static obstacles.
Parameters
target_UUIDsList of primitive UUIDs representing static obstacles
Exceptions
ValueErrorIf target_UUIDs is empty
PlantArchitectureErrorIf static obstacle configuration fails
Note
Call this method BEFORE enabling collision avoidance for best performance. Static obstacles cannot be modified or moved after being marked static.

Examples

>>> # Mark ground and building geometry as static
>>> static_uuids = ground_uuids + building_uuids
>>> plantarch.setStaticObstacles(static_uuids)
>>> # Now enable collision avoidance
>>> plantarch.enableSoftCollisionAvoidance()

Definition at line 747 of file PlantArchitecture.py.

◆ writePlantMeshVertices()

None pyhelios.PlantArchitecture.PlantArchitecture.writePlantMeshVertices ( self,
int plant_id,
Union[str, Path] filename )

Write all plant mesh vertices to file for external processing.

   This method exports all vertex coordinates (x,y,z) for every primitive in the plant,
   writing one vertex per line. Useful for external processing such as computing bounding
   volumes, convex hulls, or performing custom geometric analysis.
Parameters
plant_idID of the plant instance to export
filenamePath to output file (absolute or relative to current working directory)
Exceptions
ValueErrorIf plant_id is negative or filename is empty
PlantArchitectureErrorIf plant doesn't exist or file cannot be written

Examples

>>> # Export vertices for convex hull analysis
>>> plantarch.writePlantMeshVertices(plant_id, "plant_vertices.txt")
>>>
>>> # Use with Path object
>>> from pathlib import Path
>>> output_dir = Path("output")
>>> output_dir.mkdir(exist_ok=True)
>>> plantarch.writePlantMeshVertices(plant_id, output_dir / "vertices.txt")

Definition at line 822 of file PlantArchitecture.py.

◆ writePlantStructureXML()

None pyhelios.PlantArchitecture.PlantArchitecture.writePlantStructureXML ( self,
int plant_id,
Union[str, Path] filename )

Save plant structure to XML file for later loading.

   This method exports the complete plant architecture to an XML file, including
   all shoots, phytomers, organs, and their properties. The saved plant can be
   reloaded later using readPlantStructureXML().
Parameters
plant_idID of the plant instance to save
filenamePath to output XML file (absolute or relative to current working directory)
Exceptions
ValueErrorIf plant_id is negative or filename is empty
PlantArchitectureErrorIf plant doesn't exist or file cannot be written
Note
The XML format preserves the complete plant state including:
  • Shoot structure and hierarchy
  • Phytomer properties and development stage
  • Organ geometry and attributes
  • Growth parameters and phenological state

Examples

>>> # Save plant at current growth stage
>>> plantarch.writePlantStructureXML(plant_id, "bean_day30.xml")
>>>
>>> # Later, reload the saved plant
>>> loaded_plant_ids = plantarch.readPlantStructureXML("bean_day30.xml")
>>> print(f"Loaded {len(loaded_plant_ids)} plants")

Definition at line 871 of file PlantArchitecture.py.

◆ writeQSMCylinderFile()

None pyhelios.PlantArchitecture.PlantArchitecture.writeQSMCylinderFile ( self,
int plant_id,
Union[str, Path] filename )

Export plant structure in TreeQSM cylinder format.

   This method writes the plant structure as a series of cylinders following the
   TreeQSM format (Raumonen et al., 2013). Each row represents one cylinder with
   columns for radius, length, start position, axis direction, branch topology,
   and other structural properties. Useful for biomechanical analysis and
   quantitative structure modeling.
Parameters
plant_idID of the plant instance to export
filenamePath to output file (absolute or relative, typically .txt extension)
Exceptions
ValueErrorIf plant_id is negative or filename is empty
PlantArchitectureErrorIf plant doesn't exist or file cannot be written
Note
The TreeQSM format includes columns for:
  • Cylinder dimensions (radius, length)
  • Spatial position and orientation
  • Branch topology (parent ID, extension ID, branch ID)
  • Branch hierarchy (branch order, position in branch)
  • Quality metrics (mean absolute distance, surface coverage)

Examples

>>> # Export for biomechanical analysis
>>> plantarch.writeQSMCylinderFile(plant_id, "tree_structure_qsm.txt")
>>>
>>> # Use with external QSM tools
>>> import pandas as pd
>>> qsm_data = pd.read_csv("tree_structure_qsm.txt", sep="\\t")
>>> print(f"Tree has {len(qsm_data)} cylinders")
References
Raumonen et al. (2013) "Fast Automatic Precision Tree Models from Terrestrial Laser Scanner Data" Remote Sensing 5(2):491-520

Definition at line 928 of file PlantArchitecture.py.

Member Data Documentation

◆ _plantarch_ptr

pyhelios.PlantArchitecture.PlantArchitecture._plantarch_ptr = None
protected

Definition at line 220 of file PlantArchitecture.py.

◆ context

pyhelios.PlantArchitecture.PlantArchitecture.context = context

Definition at line 219 of file PlantArchitecture.py.


The documentation for this class was generated from the following file: