513 struct InternodeParameters {
528 std::string image_texture;
530 uint length_segments;
532 uint radial_subdivisions;
534 InternodeParameters &operator=(
const InternodeParameters &a) {
536 this->pitch = a.pitch;
537 this->pitch.resample();
538 this->phyllotactic_angle = a.phyllotactic_angle;
539 this->phyllotactic_angle.resample();
540 this->radius_initial = a.radius_initial;
541 this->radius_initial.resample();
542 this->max_vegetative_buds_per_petiole = a.max_vegetative_buds_per_petiole;
543 this->max_vegetative_buds_per_petiole.resample();
544 this->max_floral_buds_per_petiole = a.max_floral_buds_per_petiole;
545 this->max_floral_buds_per_petiole.resample();
546 this->color = a.color;
547 this->image_texture = a.image_texture;
548 this->length_segments = a.length_segments;
549 this->radial_subdivisions = a.radial_subdivisions;
555 struct PetioleParameters {
558 uint petioles_per_internode;
572 uint length_segments;
574 uint radial_subdivisions;
576 PetioleParameters &operator=(
const PetioleParameters &a) {
578 this->petioles_per_internode = a.petioles_per_internode;
579 this->pitch = a.pitch;
580 this->pitch.resample();
581 this->radius = a.radius;
582 this->radius.resample();
583 this->length = a.length;
584 this->length.resample();
585 this->curvature = a.curvature;
586 this->curvature.resample();
587 this->taper = a.taper;
588 this->taper.resample();
589 this->color = a.color;
590 this->length_segments = a.length_segments;
591 this->radial_subdivisions = a.radial_subdivisions;
597 struct LeafParameters {
615 LeafParameters &operator=(
const LeafParameters &a) {
617 this->leaves_per_petiole = a.leaves_per_petiole;
618 this->leaves_per_petiole.resample();
619 this->pitch = a.pitch;
620 this->pitch.resample();
622 this->yaw.resample();
624 this->roll.resample();
625 this->leaflet_offset = a.leaflet_offset;
626 this->leaflet_offset.resample();
627 this->leaflet_scale = a.leaflet_scale;
628 this->leaflet_scale.resample();
629 this->prototype_scale = a.prototype_scale;
630 this->prototype_scale.resample();
631 this->prototype.duplicate(a.prototype);
637 struct PeduncleParameters {
651 uint length_segments;
653 uint radial_subdivisions;
655 PeduncleParameters &operator=(
const PeduncleParameters &a) {
657 this->length = a.length;
658 this->length.resample();
659 this->radius = a.radius;
660 this->radius.resample();
661 this->pitch = a.pitch;
662 this->pitch.resample();
664 this->roll.resample();
665 this->curvature = a.curvature;
666 this->curvature.resample();
667 this->color = a.color;
668 this->length_segments = a.length_segments;
669 this->radial_subdivisions = a.radial_subdivisions;
675 struct InflorescenceParameters {
696 uint unique_prototypes;
698 InflorescenceParameters &operator=(
const InflorescenceParameters &a) {
700 this->flowers_per_peduncle = a.flowers_per_peduncle;
701 this->flowers_per_peduncle.resample();
702 this->flower_offset = a.flower_offset;
703 this->flower_offset.resample();
704 this->pitch = a.pitch;
705 this->pitch.resample();
707 this->roll.resample();
708 this->flower_prototype_scale = a.flower_prototype_scale;
709 this->flower_prototype_scale.resample();
710 this->flower_prototype_function = a.flower_prototype_function;
711 this->fruit_prototype_scale = a.fruit_prototype_scale;
712 this->fruit_prototype_scale.resample();
713 this->fruit_prototype_function = a.fruit_prototype_function;
714 this->fruit_gravity_factor_fraction = a.fruit_gravity_factor_fraction;
715 this->fruit_gravity_factor_fraction.resample();
716 this->unique_prototypes = a.unique_prototypes;
942 float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
uint rank,
PlantArchitecture *plantarchitecture_ptr,
helios::Context *context_ptr);
1054 [[nodiscard]]
bool hasLeaf()
const;
1279 helios::vec3 calculatePetioleCollisionAvoidanceDirection(
const helios::vec3 &petiole_base_origin,
const helios::vec3 &proposed_petiole_axis,
bool &collision_detection_active)
const;
1288 helios::vec3 calculateFruitCollisionAvoidanceDirection(
const helios::vec3 &fruit_base_origin,
const helios::vec3 &proposed_fruit_axis,
bool &collision_detection_active)
const;
1296 std::vector<std::vector<helios::vec3>> leaf_bases;
1297 std::vector<std::vector<std::vector<helios::vec3>>> peduncle_vertices;
1298 float internode_pitch, internode_phyllotactic_angle;
1300 std::vector<std::vector<float>> petiole_radii;
1301 std::vector<float> petiole_length;
1302 std::vector<float> petiole_pitch;
1303 std::vector<float> petiole_curvature;
1304 std::vector<std::vector<float>> leaf_size_max;
1305 std::vector<std::vector<AxisRotation>> leaf_rotation;
1307 std::vector<helios::RGBcolor> internode_colors;
1308 std::vector<helios::RGBcolor> petiole_colors;
1310 std::vector<std::vector<uint>> petiole_objIDs;
1311 std::vector<std::vector<uint>> leaf_objIDs;
1320 uint parent_shoot_ID;
1321 Shoot *parent_shoot_ptr;
1325 bool isdormant =
false;
1327 float current_internode_scale_factor = 1;
1328 std::vector<float> current_leaf_scale_factor;
1330 float old_phytomer_volume = 0;
1332 float downstream_leaf_area = 0;
1334 std::vector<std::vector<VegetativeBud>> axillary_vegetative_buds;
1335 std::vector<std::vector<FloralBud>> floral_buds;
1337 float internode_radius_initial;
1338 float internode_radius_max;
1339 float internode_length_max;
1341 bool build_context_geometry_petiole =
true;
1342 bool build_context_geometry_peduncle =
true;
1351 void updateInflorescence(
FloralBud &fbud);
1358 [[nodiscard]]
float calculatePhytomerConstructionCosts()
const;
1367 [[nodiscard]]
float calculateFlowerConstructionCosts(
const FloralBud &fbud)
const;
1374 [[nodiscard]]
float calculateFruitConstructionCosts(
const FloralBud &fbud)
const;
1376 friend struct Shoot;
1630 static int selfTest(
int argc,
char **argv);
1764 void setPlantPhenologicalThresholds(
uint plantID,
float time_to_dormancy_break,
float time_to_flower_initiation,
float time_to_flower_opening,
float time_to_fruit_set,
float time_to_fruit_maturity,
float time_to_dormancy,
1765 float max_leaf_lifespan = 1e6,
bool is_evergreen =
false);
1799 void advanceTime(
int time_step_years,
float time_step_days);
1813 void advanceTime(
const std::vector<uint> &plantIDs,
float time_step_days);
1857 uint addBaseStemShoot(
uint plantID,
uint current_node_number,
const AxisRotation &base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
1858 float radius_taper,
const std::string &shoot_type_label);
1874 uint appendShoot(
uint plantID,
int parent_shoot_ID,
uint current_node_number,
const AxisRotation &base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
1875 float radius_taper,
const std::string &shoot_type_label);
1893 uint addChildShoot(
uint plantID,
int parent_shoot_ID,
uint parent_node_index,
uint current_node_number,
const AxisRotation &shoot_base_rotation,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
1894 float leaf_scale_factor_fraction,
float radius_taper,
const std::string &shoot_type_label,
uint petiole_index = 0);
1911 uint addEpicormicShoot(
uint plantID,
int parent_shoot_ID,
float parent_position_fraction,
uint current_node_number,
float zenith_perturbation_degrees,
float internode_radius,
float internode_length_max,
1912 float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
float radius_taper,
const std::string &shoot_type_label);
1925 int appendPhytomerToShoot(
uint plantID,
uint shootID,
const PhytomerParameters &phytomer_parameters,
float internode_radius,
float internode_length_max,
float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction);
1960 void enableSoftCollisionAvoidance(
const std::vector<uint> &target_object_UUIDs = {},
const std::vector<uint> &target_object_IDs = {},
bool enable_petiole_collision =
false,
bool enable_fruit_collision =
false);
1994 void setCollisionRelevantOrgans(
bool include_internodes,
bool include_leaves,
bool include_petioles,
bool include_flowers,
bool include_fruit);
2009 void enableSolidObstacleAvoidance(
const std::vector<uint> &obstacle_UUIDs,
float avoidance_distance = 0.5f,
bool enable_fruit_adjustment =
false,
bool enable_obstacle_pruning =
false);
2027 void enableAttractionPoints(
const std::vector<helios::vec3> &attraction_points,
float view_half_angle_deg = 80.0f,
float look_ahead_distance = 0.1f,
float attraction_weight = 0.6f);
2051 void setAttractionParameters(
float view_half_angle_deg,
float look_ahead_distance,
float attraction_weight,
float obstacle_reduction_factor = 0.75f);
2061 void enableAttractionPoints(
uint plantID,
const std::vector<helios::vec3> &attraction_points,
float view_half_angle_deg = 80.0f,
float look_ahead_distance = 0.1f,
float attraction_weight = 0.6f);
2091 void setAttractionParameters(
uint plantID,
float view_half_angle_deg,
float look_ahead_distance,
float attraction_weight,
float obstacle_reduction_factor = 0.75f);
2225 void setPlantLeafAngleDistribution(
uint plantID,
float Beta_mu_inclination,
float Beta_nu_inclination,
float eccentricity,
float ellipse_rotation_degrees)
const;
2241 void setPlantLeafAngleDistribution(
const std::vector<uint> &plantIDs,
float Beta_mu_inclination,
float Beta_nu_inclination,
float eccentricity,
float ellipse_rotation_degrees)
const;
2349 [[nodiscard]] std::vector<helios::vec3>
getPlantBasePosition(
const std::vector<uint> &plantIDs)
const;
2427 [[nodiscard]] std::vector<helios::vec3>
getPlantLeafBases(
const std::vector<uint> &plantIDs)
const;
2526 [[nodiscard]] std::vector<uint>
getAllUUIDs()
const;
2609 uint generatePlantFromString(
const std::string &generation_string,
const std::map<std::string, PhytomerParameters> &phytomer_parameters);
2655 friend struct Shoot;
2659 void clearBVHCache()
const;
2662 void rebuildBVHForTimestep();
2675 void setPlantAttractionPoints(
uint plantID,
const std::vector<helios::vec3> &attraction_points,
float view_half_angle_deg = 80.0f,
float look_ahead_distance = 0.1f,
float attraction_weight = 0.6f,
float obstacle_reduction_factor = 0.75f);
2680 std::minstd_rand0 *generator =
nullptr;
2682 uint plant_count = 0;
2684 std::string current_plant_model;
2687 std::map<std::string, std::function<void()>> shoot_initializers;
2688 std::map<std::string, std::function<
uint(
const helios::vec3 &)>> plant_builders;
2690 std::map<uint, PlantInstance> plant_instances;
2692 [[nodiscard]] std::string makeShootString(
const std::string ¤t_string,
const std::shared_ptr<Shoot> &shoot,
const std::vector<std::shared_ptr<Shoot>> &shoot_tree)
const;
2694 std::map<std::string, ShootParameters> shoot_types;
2698 std::map<uint, std::vector<std::vector<uint>>> unique_leaf_prototype_objIDs;
2701 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions,
bool flower_is_open), std::vector<uint>> unique_open_flower_prototype_objIDs;
2703 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions,
bool flower_is_open), std::vector<uint>> unique_closed_flower_prototype_objIDs;
2705 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions), std::vector<uint>> unique_fruit_prototype_objIDs;
2707 bool build_context_geometry_internode =
true;
2708 bool build_context_geometry_petiole =
true;
2709 bool build_context_geometry_peduncle =
true;
2711 float ground_clipping_height = -99999;
2716 void registerPlantModel(
const std::string &name, std::function<
void()> shoot_init, std::function<
uint(
const helios::vec3 &)> plant_build);
2719 void initializePlantModelRegistrations();
2721 void parseStringShoot(
const std::string &LString_shoot,
uint plantID,
int parentID,
uint parent_node,
const std::map<std::string, PhytomerParameters> &phytomer_parameters,
ShootParameters &shoot_parameters);
2723 void parseShootArgument(
const std::string &shoot_argument,
const std::map<std::string, PhytomerParameters> &phytomer_parameters,
ShootParameters &shoot_parameters,
AxisRotation &base_rotation, std::string &phytomer_label);
2725 void parseInternodeArgument(
const std::string &internode_argument,
float &internode_radius,
float &internode_length,
PhytomerParameters &phytomer_parameters);
2727 void parsePetioleArgument(
const std::string &petiole_argument,
PhytomerParameters &phytomer_parameters);
2729 void parseLeafArgument(
const std::string &leaf_argument,
PhytomerParameters &phytomer_parameters);
2731 void initializeDefaultShoots(
const std::string &plant_label);
2733 [[nodiscard]]
bool detectGroundCollision(
uint objID);
2735 [[nodiscard]]
bool detectGroundCollision(
const std::vector<uint> &objID)
const;
2737 void setPlantLeafAngleDistribution_private(
const std::vector<uint> &plantIDs,
float Beta_mu_inclination,
float Beta_nu_inclination,
float eccentricity_azimuth,
float ellipse_rotation_azimuth_degrees,
bool set_elevation,
bool set_azimuth)
const;
2739 static float interpolateTube(
const std::vector<float> &P,
float frac);
2744 std::map<std::string, bool> output_object_data;
2748 void incrementPhytomerInternodeGirth(
uint plantID,
uint shootID,
uint node_number,
float dt,
bool update_context_geometry);
2749 void incrementPhytomerInternodeGirth_carb(
uint plantID,
uint shootID,
uint node_number,
float dt,
bool update_context_geometry);
2751 void pruneGroundCollisions(
uint plantID);
2753 void pruneSolidBoundaryCollisions();
2757 void accumulateShootPhotosynthesis()
const;
2759 void subtractShootMaintenanceCarbon(
float dt)
const;
2760 void subtractShootGrowthCarbon();
2762 void checkCarbonPool_abortOrgans(
float dt);
2763 void checkCarbonPool_adjustPhyllochron(
float dt);
2764 void checkCarbonPool_transferCarbon(
float dt);
2766 bool carbon_model_enabled =
false;
2774 bool owns_collision_detection =
false;
2777 bool collision_detection_enabled =
false;
2780 std::vector<uint> collision_target_UUIDs;
2783 std::vector<uint> collision_target_object_IDs;
2786 float collision_cone_half_angle_rad = 80.f *
M_PI / 180.f;
2789 float collision_cone_height = 0.1f;
2792 int collision_sample_count = 256;
2795 float collision_inertia_weight = 0.4f;
2798 int geometry_update_frequency = 3;
2801 bool force_update_on_collision =
true;
2804 bool collision_include_internodes =
false;
2805 bool collision_include_leaves =
true;
2806 bool collision_include_petioles =
false;
2807 bool collision_include_flowers =
false;
2808 bool collision_include_fruit =
false;
2811 bool petiole_collision_detection_enabled =
false;
2814 bool fruit_collision_detection_enabled =
false;
2817 int geometry_update_counter = 0;
2820 mutable bool collision_avoidance_applied =
false;
2823 bool spatial_filtering_enabled =
false;
2826 float spatial_max_distance = 5.0f;
2829 mutable bool bvh_cached_for_current_growth =
false;
2830 mutable std::vector<uint> cached_target_geometry;
2831 mutable std::vector<uint> cached_filtered_geometry;
2834 bool solid_obstacle_avoidance_enabled =
false;
2835 std::vector<uint> solid_obstacle_UUIDs;
2836 float solid_obstacle_avoidance_distance = 0.5f;
2837 float solid_obstacle_minimum_distance = 0.05f;
2838 bool solid_obstacle_fruit_adjustment_enabled =
false;
2839 bool solid_obstacle_pruning_enabled =
false;
2844 bool attraction_points_enabled =
false;
2847 std::vector<helios::vec3> attraction_points;
2850 float attraction_cone_half_angle_rad = 80.f *
M_PI / 180.f;
2853 float attraction_cone_height = 0.1f;
2856 float attraction_weight = 0.6f;
2859 float attraction_obstacle_reduction_factor = 0.5f;
2862 bool printmessages =
true;
2866 void initializeAlmondTreeShoots();
2870 void initializeAppleTreeShoots();
2874 void initializeAsparagusShoots();
2878 void initializeBindweedShoots();
2882 void initializeBeanShoots();
2886 void initializeCapsicumShoots();
2890 void initializeCheeseweedShoots();
2894 void initializeCowpeaShoots();
2898 void initializeGrapevineVSPShoots();
2902 void initializeGrapevineWyeShoots();
2906 void initializeGroundCherryWeedShoots();
2910 void initializeMaizeShoots();
2914 void initializeOliveTreeShoots();
2918 void initializePistachioTreeShoots();
2922 void initializePuncturevineShoots();
2926 void initializeEasternRedbudShoots();
2930 void initializeRiceShoots();
2934 void initializeButterLettuceShoots();
2938 void initializeSoybeanShoots();
2942 void initializeSorghumShoots();
2946 void initializeStrawberryShoots();
2950 void initializeSugarbeetShoots();
2954 void initializeTomatoShoots();
2958 void initializeCherryTomatoShoots();
2962 void initializeWalnutTreeShoots();
2966 void initializeWheatShoots();