570 struct InternodeParameters {
585 std::string image_texture;
587 uint length_segments;
589 uint radial_subdivisions;
591 InternodeParameters &operator=(
const InternodeParameters &a) {
593 this->pitch = a.pitch;
594 if (a.pitch.distribution !=
"constant")
595 this->pitch.resample();
596 this->phyllotactic_angle = a.phyllotactic_angle;
597 if (a.phyllotactic_angle.distribution !=
"constant")
598 this->phyllotactic_angle.resample();
599 this->radius_initial = a.radius_initial;
600 if (a.radius_initial.distribution !=
"constant")
601 this->radius_initial.resample();
602 this->max_vegetative_buds_per_petiole = a.max_vegetative_buds_per_petiole;
603 if (a.max_vegetative_buds_per_petiole.distribution !=
"constant")
604 this->max_vegetative_buds_per_petiole.resample();
605 this->max_floral_buds_per_petiole = a.max_floral_buds_per_petiole;
606 if (a.max_floral_buds_per_petiole.distribution !=
"constant")
607 this->max_floral_buds_per_petiole.resample();
608 this->color = a.color;
609 this->image_texture = a.image_texture;
610 this->length_segments = a.length_segments;
611 this->radial_subdivisions = a.radial_subdivisions;
617 struct PetioleParameters {
620 uint petioles_per_internode;
634 uint length_segments;
636 uint radial_subdivisions;
638 PetioleParameters &operator=(
const PetioleParameters &a) {
640 this->petioles_per_internode = a.petioles_per_internode;
641 this->pitch = a.pitch;
642 if (a.pitch.distribution !=
"constant")
643 this->pitch.resample();
644 this->radius = a.radius;
645 if (a.radius.distribution !=
"constant")
646 this->radius.resample();
647 this->length = a.length;
648 if (a.length.distribution !=
"constant")
649 this->length.resample();
650 this->curvature = a.curvature;
651 if (a.curvature.distribution !=
"constant")
652 this->curvature.resample();
653 this->taper = a.taper;
654 if (a.taper.distribution !=
"constant")
655 this->taper.resample();
656 this->color = a.color;
657 this->length_segments = a.length_segments;
658 this->radial_subdivisions = a.radial_subdivisions;
664 struct LeafParameters {
682 LeafParameters &operator=(
const LeafParameters &a) {
684 this->leaves_per_petiole = a.leaves_per_petiole;
685 if (a.leaves_per_petiole.distribution !=
"constant")
686 this->leaves_per_petiole.resample();
687 this->pitch = a.pitch;
688 if (a.pitch.distribution !=
"constant")
689 this->pitch.resample();
691 if (a.yaw.distribution !=
"constant")
692 this->yaw.resample();
694 if (a.roll.distribution !=
"constant")
695 this->roll.resample();
696 this->leaflet_offset = a.leaflet_offset;
697 if (a.leaflet_offset.distribution !=
"constant")
698 this->leaflet_offset.resample();
699 this->leaflet_scale = a.leaflet_scale;
700 if (a.leaflet_scale.distribution !=
"constant")
701 this->leaflet_scale.resample();
702 this->prototype_scale = a.prototype_scale;
703 if (a.prototype_scale.distribution !=
"constant")
704 this->prototype_scale.resample();
705 this->prototype.duplicate(a.prototype);
711 struct PeduncleParameters {
725 uint length_segments;
727 uint radial_subdivisions;
729 PeduncleParameters &operator=(
const PeduncleParameters &a) {
731 this->length = a.length;
732 if (a.length.distribution !=
"constant")
733 this->length.resample();
734 this->radius = a.radius;
735 if (a.radius.distribution !=
"constant")
736 this->radius.resample();
737 this->pitch = a.pitch;
738 if (a.pitch.distribution !=
"constant")
739 this->pitch.resample();
741 if (a.roll.distribution !=
"constant")
742 this->roll.resample();
743 this->curvature = a.curvature;
744 if (a.curvature.distribution !=
"constant")
745 this->curvature.resample();
746 this->color = a.color;
747 this->length_segments = a.length_segments;
748 this->radial_subdivisions = a.radial_subdivisions;
754 struct InflorescenceParameters {
775 uint unique_prototypes;
777 InflorescenceParameters &operator=(
const InflorescenceParameters &a) {
779 this->flowers_per_peduncle = a.flowers_per_peduncle;
780 this->flowers_per_peduncle.resample();
781 this->flower_offset = a.flower_offset;
782 this->flower_offset.resample();
783 this->pitch = a.pitch;
784 this->pitch.resample();
786 this->roll.resample();
787 this->flower_prototype_scale = a.flower_prototype_scale;
788 this->flower_prototype_scale.resample();
789 this->flower_prototype_function = a.flower_prototype_function;
790 this->fruit_prototype_scale = a.fruit_prototype_scale;
791 this->fruit_prototype_scale.resample();
792 this->fruit_prototype_function = a.fruit_prototype_function;
793 this->fruit_gravity_factor_fraction = a.fruit_gravity_factor_fraction;
794 this->fruit_gravity_factor_fraction.resample();
795 this->unique_prototypes = a.unique_prototypes;
1026 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);
1138 [[nodiscard]]
bool hasLeaf()
const;
1373 helios::vec3 calculatePetioleCollisionAvoidanceDirection(
const helios::vec3 &petiole_base_origin,
const helios::vec3 &proposed_petiole_axis,
bool &collision_detection_active)
const;
1382 helios::vec3 calculateFruitCollisionAvoidanceDirection(
const helios::vec3 &fruit_base_origin,
const helios::vec3 &proposed_fruit_axis,
bool &collision_detection_active)
const;
1390 std::vector<std::vector<helios::vec3>> leaf_bases;
1391 std::vector<std::vector<std::vector<helios::vec3>>> peduncle_vertices;
1392 std::vector<std::vector<std::vector<float>>> peduncle_radii;
1393 std::vector<std::vector<float>> peduncle_length;
1394 std::vector<std::vector<float>> peduncle_radius;
1395 std::vector<std::vector<float>> peduncle_pitch;
1396 std::vector<std::vector<float>> peduncle_curvature;
1397 float internode_pitch, internode_phyllotactic_angle;
1399 std::vector<std::vector<float>> petiole_radii;
1400 std::vector<float> petiole_length;
1401 std::vector<float> petiole_pitch;
1402 std::vector<float> petiole_curvature;
1403 std::vector<float> petiole_taper;
1404 std::vector<helios::vec3> petiole_axis_initial;
1405 std::vector<helios::vec3> petiole_rotation_axis;
1406 std::vector<std::vector<float>> leaf_size_max;
1407 std::vector<std::vector<AxisRotation>> leaf_rotation;
1409 std::vector<helios::RGBcolor> internode_colors;
1410 std::vector<helios::RGBcolor> petiole_colors;
1412 std::vector<std::vector<uint>> petiole_objIDs;
1413 std::vector<std::vector<uint>> leaf_objIDs;
1422 uint parent_shoot_ID;
1423 Shoot *parent_shoot_ptr;
1427 bool isdormant =
false;
1429 float current_internode_scale_factor = 1;
1430 std::vector<float> current_leaf_scale_factor;
1432 float old_phytomer_volume = 0;
1434 float downstream_leaf_area = 0;
1436 std::vector<std::vector<VegetativeBud>> axillary_vegetative_buds;
1437 std::vector<std::vector<FloralBud>> floral_buds;
1439 float internode_radius_initial;
1440 float internode_radius_max;
1441 float internode_length_max;
1446 bool build_context_geometry_petiole =
true;
1447 bool build_context_geometry_peduncle =
true;
1456 void updateInflorescence(
FloralBud &fbud);
1474 void createInflorescenceGeometry(
FloralBud &fbud,
const helios::vec3 &fruit_base,
const helios::vec3 &peduncle_axis,
float pitch,
float roll,
float azimuth,
float yaw_compound,
float scale_factor,
bool is_open_flower);
1481 [[nodiscard]]
float calculatePhytomerConstructionCosts()
const;
1490 [[nodiscard]]
float calculateFlowerConstructionCosts(
const FloralBud &fbud)
const;
1497 [[nodiscard]]
float calculateFruitConstructionCosts(
const FloralBud &fbud)
const;
1499 friend struct Shoot;
1773 static int selfTest(
int argc,
char **argv);
1820 const std::map<std::string, float> &build_parameters = {});
1868 [[nodiscard]] std::vector<std::string>
listShootTypeLabels(
const std::string &plant_model_name);
1938 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,
1939 float max_leaf_lifespan = 1e6,
bool is_evergreen =
false);
1973 void advanceTime(
int time_step_years,
float time_step_days);
1987 void advanceTime(
const std::vector<uint> &plantIDs,
float time_step_days);
2031 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,
2032 float radius_taper,
const std::string &shoot_type_label);
2048 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,
2049 float radius_taper,
const std::string &shoot_type_label);
2067 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,
2068 float leaf_scale_factor_fraction,
float radius_taper,
const std::string &shoot_type_label,
uint petiole_index = 0);
2085 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,
2086 float internode_length_scale_factor_fraction,
float leaf_scale_factor_fraction,
float radius_taper,
const std::string &shoot_type_label);
2099 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);
2134 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);
2168 void setCollisionRelevantOrgans(
bool include_internodes,
bool include_leaves,
bool include_petioles,
bool include_flowers,
bool include_fruit);
2183 void enableSolidObstacleAvoidance(
const std::vector<uint> &obstacle_UUIDs,
float avoidance_distance = 0.5f,
bool enable_fruit_adjustment =
false,
bool enable_obstacle_pruning =
false);
2201 void enableAttractionPoints(
const std::vector<helios::vec3> &attraction_points,
float view_half_angle_deg = 45.0f,
float look_ahead_distance = 0.1f,
float attraction_weight = 0.6f);
2225 void setAttractionParameters(
float view_half_angle_deg,
float look_ahead_distance,
float attraction_weight,
float obstacle_reduction_factor = 0.75f);
2235 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);
2265 void setAttractionParameters(
uint plantID,
float view_half_angle_deg,
float look_ahead_distance,
float attraction_weight,
float obstacle_reduction_factor = 0.75f);
2399 void setPlantLeafAngleDistribution(
uint plantID,
float Beta_mu_inclination,
float Beta_nu_inclination,
float eccentricity,
float ellipse_rotation_degrees)
const;
2415 void setPlantLeafAngleDistribution(
const std::vector<uint> &plantIDs,
float Beta_mu_inclination,
float Beta_nu_inclination,
float eccentricity,
float ellipse_rotation_degrees)
const;
2531 [[nodiscard]] std::vector<helios::vec3>
getPlantBasePosition(
const std::vector<uint> &plantIDs)
const;
2609 [[nodiscard]] std::vector<helios::vec3>
getPlantLeafBases(
const std::vector<uint> &plantIDs)
const;
2740 [[nodiscard]] std::vector<uint>
getAllUUIDs()
const;
2893 uint generatePlantFromString(
const std::string &generation_string,
const std::map<std::string, PhytomerParameters> &phytomer_parameters);
2960 friend struct Shoot;
2974 float getParameterValue(
const std::map<std::string, float> &build_parameters,
const std::string ¶meter_name,
float default_value,
float min_value,
float max_value,
const std::string ¶meter_description)
const;
2977 void clearBVHCache()
const;
2980 void rebuildBVHForTimestep();
2993 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);
3007 std::minstd_rand0 *generator =
nullptr;
3009 uint plant_count = 0;
3011 std::string current_plant_model;
3014 std::map<std::string, float> current_build_parameters;
3017 std::map<std::string, std::function<void()>> shoot_initializers;
3018 std::map<std::string, std::function<
uint(
const helios::vec3 &)>> plant_builders;
3019 std::map<std::string, std::string> plant_type_map;
3021 std::map<uint, PlantInstance> plant_instances;
3023 [[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;
3025 std::map<std::string, ShootParameters> shoot_types;
3029 std::map<uint, std::vector<std::vector<uint>>> unique_leaf_prototype_objIDs;
3032 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions,
bool flower_is_open), std::vector<uint>> unique_open_flower_prototype_objIDs;
3034 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions,
bool flower_is_open), std::vector<uint>> unique_closed_flower_prototype_objIDs;
3036 std::map<
uint (*)(
helios::Context *context_ptr,
uint subdivisions), std::vector<uint>> unique_fruit_prototype_objIDs;
3038 bool build_context_geometry_internode =
true;
3039 bool build_context_geometry_petiole =
true;
3040 bool build_context_geometry_peduncle =
true;
3042 float ground_clipping_height = -99999;
3044 void validateShootTypes(
ShootParameters &shoot_parameters,
const std::map<std::string, ShootParameters> &shoot_types_ref)
const;
3047 void registerPlantModel(
const std::string &name, std::function<
void()> shoot_init, std::function<
uint(
const helios::vec3 &)> plant_build,
const std::string &plant_type =
"herbaceous");
3050 void initializePlantModelRegistrations();
3052 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);
3054 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);
3056 void parseInternodeArgument(
const std::string &internode_argument,
float &internode_radius,
float &internode_length,
PhytomerParameters &phytomer_parameters);
3058 void parsePetioleArgument(
const std::string &petiole_argument,
PhytomerParameters &phytomer_parameters);
3060 void parseLeafArgument(
const std::string &leaf_argument,
PhytomerParameters &phytomer_parameters);
3062 void initializeDefaultShoots(
const std::string &plant_label);
3064 [[nodiscard]]
bool detectGroundCollision(
uint objID);
3066 [[nodiscard]]
bool detectGroundCollision(
const std::vector<uint> &objID)
const;
3068 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;
3070 static float interpolateTube(
const std::vector<float> &P,
float frac);
3075 std::map<std::string, bool> output_object_data;
3079 void incrementPhytomerInternodeGirth(
uint plantID,
uint shootID,
uint node_number,
float dt,
bool update_context_geometry);
3080 void incrementPhytomerInternodeGirth_carb(
uint plantID,
uint shootID,
uint node_number,
float dt,
bool update_context_geometry);
3082 void pruneGroundCollisions(
uint plantID);
3084 void pruneSolidBoundaryCollisions();
3088 void accumulateShootPhotosynthesis()
const;
3090 void subtractShootMaintenanceCarbon(
float dt)
const;
3091 void subtractShootGrowthCarbon();
3093 void checkCarbonPool_abortOrgans(
float dt);
3094 void checkCarbonPool_adjustPhyllochron(
float dt);
3095 void checkCarbonPool_transferCarbon(
float dt);
3097 bool carbon_model_enabled =
false;
3101 void accumulateLeafNitrogen(
float dt);
3102 void remobilizeNitrogen(
float dt);
3103 void updateNitrogenStressFactor();
3104 void removeFruitNitrogen();
3106 bool nitrogen_model_enabled =
false;
3114 bool owns_collision_detection =
false;
3117 bool collision_detection_enabled =
false;
3120 std::vector<uint> collision_target_UUIDs;
3123 std::vector<uint> collision_target_object_IDs;
3126 float collision_cone_half_angle_rad = 80.f *
M_PI / 180.f;
3129 float collision_cone_height = 0.1f;
3132 int collision_sample_count = 256;
3135 float collision_inertia_weight = 0.4f;
3138 int geometry_update_frequency = 3;
3141 bool force_update_on_collision =
true;
3144 bool collision_include_internodes =
false;
3145 bool collision_include_leaves =
true;
3146 bool collision_include_petioles =
false;
3147 bool collision_include_flowers =
false;
3148 bool collision_include_fruit =
false;
3151 bool petiole_collision_detection_enabled =
false;
3154 bool fruit_collision_detection_enabled =
false;
3157 int geometry_update_counter = 0;
3160 mutable bool collision_avoidance_applied =
false;
3163 bool spatial_filtering_enabled =
false;
3166 float spatial_max_distance = 5.0f;
3169 mutable bool bvh_cached_for_current_growth =
false;
3170 mutable std::vector<uint> cached_target_geometry;
3171 mutable std::vector<uint> cached_filtered_geometry;
3174 bool solid_obstacle_avoidance_enabled =
false;
3175 std::vector<uint> solid_obstacle_UUIDs;
3176 float solid_obstacle_avoidance_distance = 0.5f;
3177 float solid_obstacle_minimum_distance = 0.05f;
3178 bool solid_obstacle_fruit_adjustment_enabled =
false;
3179 bool solid_obstacle_pruning_enabled =
false;
3184 bool attraction_points_enabled =
false;
3187 std::vector<helios::vec3> attraction_points;
3190 float attraction_cone_half_angle_rad = 80.f *
M_PI / 180.f;
3193 float attraction_cone_height = 0.1f;
3196 float attraction_weight = 0.6f;
3199 float attraction_obstacle_reduction_factor = 0.5f;
3202 bool printmessages =
true;
3206 void initializeAlmondTreeShoots();
3210 void initializeAlmondTreeAldrichShoots();
3214 void initializeAlmondTreeWoodColonyShoots();
3218 void initializeAppleTreeShoots();
3222 void initializeAppleFruitingWallShoots();
3226 void initializeAsparagusShoots();
3230 void initializeBindweedShoots();
3234 void initializeBeanShoots();
3238 void initializeBougainvilleaShoots();
3242 void initializeCapsicumShoots();
3246 void initializeCheeseweedShoots();
3250 void initializeCowpeaShoots();
3254 void initializeGrapevineVSPShoots();
3258 void initializeGrapevineWyeShoots();
3262 void initializeGroundCherryWeedShoots();
3266 void initializeMaizeShoots();
3270 void initializeOliveTreeShoots();
3274 void initializePistachioTreeShoots();
3278 void initializePuncturevineShoots();
3282 void initializeEasternRedbudShoots();
3286 void initializeRiceShoots();
3290 void initializeButterLettuceShoots();
3294 void initializeSoybeanShoots();
3298 void initializeSorghumShoots();
3302 void initializeStrawberryShoots();
3306 void initializeSugarbeetShoots();
3310 void initializeTomatoShoots();
3314 void initializeCherryTomatoShoots();
3318 void initializeWalnutTreeShoots();
3322 void initializeWheatShoots();