19using namespace helios;
29 }
catch (
const std::runtime_error &) {
35 std::string leaf_texture;
37 helios_runtime_error(
"ERROR (PlantArchitecture): Leaf prototype texture file was not specified.");
41 helios_runtime_error(
"ERROR (PlantArchitecture): Leaf prototype texture file for compound leaf index " + std::to_string(compound_leaf_index) +
" was not found.");
48 std::vector<uint> UUIDs;
51 uint Ny = ceil(prototype_parameters->leaf_aspect_ratio.val() *
float(Nx));
57 const float dx = 1.f / float(Nx);
58 const float dy = prototype_parameters->leaf_aspect_ratio.val() / float(Ny);
60 std::vector<std::vector<vec3>> vertices;
63 for (
int j = 0; j <= Ny; j++) {
65 for (
int i = 0; i <= Nx; i++) {
67 const float x = float(i) * dx;
68 const float y = float(j) * dy - 0.5f * prototype_parameters->leaf_aspect_ratio.val();
78 float z_ycurve = prototype_parameters->
lateral_curvature.val() * powf(y / prototype_parameters->leaf_aspect_ratio.val(), 4);
83 z_petiole = fmin(0.1f, prototype_parameters->
petiole_roll.val() * powf(7.f * y / prototype_parameters->leaf_aspect_ratio.val(), 4) * exp(-70.f * (x))) -
90 z_wave = (2.f * fabs(y) * prototype_parameters->
wave_amplitude.val() * sinf((x + 0.5f *
float(j >= 0.5 * Ny)) *
M_PI / prototype_parameters->
wave_period.val()));
93 vertices.at(j).at(i) =
make_vec3(x, y_fold, z_fold + z_ycurve + z_wave + z_petiole);
102 if (x <= prototype_parameters->leaf_buckle_length.val() && x + dx > prototype_parameters->
leaf_buckle_length.val()) {
111 for (
int j = 0; j < Ny; j++) {
112 for (
int i = 0; i < Nx; i++) {
114 const float x = float(i) * dx;
115 const float y = float(j) * dy - 0.5f * prototype_parameters->leaf_aspect_ratio.val();
116 vec2 uv0(x, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
117 vec2 uv1(x + dx, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
118 vec2 uv2(x + dx, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
119 vec2 uv3(x, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
121 vec3 v0 = vertices.at(j).at(i);
122 vec3 v1 = vertices.at(j).at(i + 1);
123 vec3 v2 = vertices.at(j + 1).at(i + 1);
124 vec3 v3 = vertices.at(j + 1).at(i);
127 uint uuid1 = context_ptr->
addTriangle(v0, v1, v2, leaf_texture.c_str(), uv0, uv1, uv2);
129 UUIDs.push_back(uuid1);
135 uint uuid2 = context_ptr->
addTriangle(v0, v2, v3, leaf_texture.c_str(), uv0, uv2, uv3);
137 UUIDs.push_back(uuid2);
147 std::vector<uint> UUIDs_petiolule = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/PetiolulePrototype.obj",
make_vec3(0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
149 UUIDs.insert(UUIDs.end(), UUIDs_petiolule.begin(), UUIDs_petiolule.end());
152 prototype_parameters->leaf_aspect_ratio.resample();
170 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/AlmondHull.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
176 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/AlmondFlower.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
181void AlmondPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
183 if (phytomer->internode_length_max < 0.01) {
184 phytomer->setInternodeMaxRadius(0.005);
185 phytomer->setVegetativeBudState(BUD_DEAD);
186 phytomer->scaleLeafPrototypeScale(0.8);
187 phytomer->setFloralBudState(BUD_DEAD);
188 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 7;
198void AlmondPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
202 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/AppleFruit.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
208 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/AlmondFlower.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
213void ApplePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
215 if (phytomer->internode_length_max < 0.01) {
216 phytomer->setInternodeMaxRadius(0.005);
217 phytomer->setVegetativeBudState(BUD_DEAD);
218 phytomer->scaleLeafPrototypeScale(0.8);
219 phytomer->setFloralBudState(BUD_DEAD);
220 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 6;
224void ApplePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
229 float curve_magnitude = context_ptr->
randu(0.f, 0.2f);
231 std::vector<vec3> nodes;
233 nodes.push_back(
make_vec3(context_ptr->
randu(0.4f, 0.7f), 0, -0.25f * curve_magnitude));
234 nodes.push_back(
make_vec3(0.95, 0, -0.9f * curve_magnitude));
235 nodes.push_back(
make_vec3(1, 0, -curve_magnitude));
237 std::vector<float> radius;
238 radius.push_back(0.015);
239 radius.push_back(0.015);
240 radius.push_back(0.015);
241 radius.push_back(0.0);
243 std::vector<RGBcolor> colors;
244 colors.push_back(RGB::forestgreen);
245 colors.push_back(RGB::forestgreen);
246 colors.push_back(RGB::forestgreen);
247 colors.push_back(RGB::forestgreen);
254void AsparagusPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
257 if (shoot_node_index <= 2) {
258 phytomer->scaleLeafPrototypeScale(0.6);
259 phytomer->setVegetativeBudState(BUD_DEAD);
264 std::vector<uint> UUIDs;
265 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanLeaf_unifoliate.obj",
true);
272 std::vector<uint> UUIDs;
273 if (compound_leaf_index == 0) {
274 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanLeaf_tip.obj",
true);
275 }
else if (compound_leaf_index < 0) {
276 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanLeaf_left.obj",
true);
278 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanLeaf_right.obj",
true);
285 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanPod.obj",
true);
291 std::vector<uint> UUIDs;
292 if (flower_is_open) {
293 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanFlower_open_white.obj",
true);
295 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanFlower_closed_white.obj",
true);
301void BeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
303 if (shoot_node_index > 5 || phytomer->rank > 1) {
304 phytomer->setVegetativeBudState(BUD_DEAD);
306 phytomer->setFloralBudState(BUD_DEAD);
310 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
311 phytomer->scaleLeafPrototypeScale(leaf_scale);
314 if (phytomer->rank == 0) {
315 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
316 phytomer->scaleInternodeMaxLength(inode_scale);
321 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BindweedFlower.obj",
true);
327 std::string OBJ_file;
328 if (context_ptr->
randn() < 0.4) {
329 OBJ_file =
"CapsicumFruit_green.obj";
331 OBJ_file =
"CapsicumFruit_red.obj";
334 std::vector<uint> UUIDs = context_ptr->
loadOBJ(OBJ_file.c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
338void CapsicumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
340 if (shoot_node_index < 6 && phytomer->rank == 0) {
341 phytomer->setVegetativeBudState(BUD_DEAD);
342 phytomer->setFloralBudState(BUD_DEAD);
343 phytomer->removeLeaf();
346 if (phytomer->rank >= 2) {
347 phytomer->setVegetativeBudState(BUD_DEAD);
348 phytomer->setFloralBudState(BUD_DEAD);
352 float leaf_scale = std::min(1.f, 0.6f + 0.4f * shoot_node_index / 5.f);
353 phytomer->scaleLeafPrototypeScale(leaf_scale);
356 if (phytomer->rank == 0) {
357 float inode_scale = std::min(1.f, 0.05f + 0.95f * plant_age / 15.f);
358 phytomer->scaleInternodeMaxLength(inode_scale);
363 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CheeseweedLeaf.obj",
true);
369 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaLeaf_unifoliate.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
376 std::vector<uint> UUIDs;
377 if (compound_leaf_index < 0) {
378 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaLeaf_left_highres.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
379 }
else if (compound_leaf_index == 0) {
380 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaLeaf_tip_highres.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
382 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaLeaf_right_highres.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
389 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaPod.obj",
make_vec3(0., 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
395 std::vector<uint> UUIDs;
396 if (flower_is_open) {
397 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaFlower_open_yellow.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
399 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/CowpeaFlower_closed_yellow.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
405void CowpeaPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
407 if (shoot_node_index > 5 || phytomer->rank > 1) {
408 phytomer->setVegetativeBudState(BUD_DEAD);
410 phytomer->setFloralBudState(BUD_DEAD);
414 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
415 phytomer->scaleLeafPrototypeScale(leaf_scale);
418 if (phytomer->rank == 0) {
419 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
420 phytomer->scaleInternodeMaxLength(inode_scale);
425float random_float(
float min,
float max) {
426 return min +
static_cast<float>(rand()) / (
static_cast<float>(RAND_MAX / (
max -
min)));
431 float distance = std::sqrt(std::pow(center1.
x - center2.
x, 2) + std::pow(center1.
y - center2.
y, 2) + std::pow(center1.
z - center2.
z, 2));
432 return distance < (radius1 + radius2);
439 float base_radius = 2.f;
440 float taper_factor = 0.6f;
441 float grape_radius = 0.25f;
443 std::vector<std::pair<helios::vec3, float>> grapes;
444 float z_step = height / num_grapes;
448 grapes.push_back({first_center, grape_radius});
451 int max_attempts = 100;
453 for (
int i = 1; i < num_grapes; ++i) {
454 float z = i * z_step;
456 float taper_radius = base_radius * (1.0f - taper_factor * (z / height));
460 while (!placed && attempts < max_attempts) {
462 int reference_idx = rand() % grapes.size();
463 const helios::vec3 &reference_center = grapes[reference_idx].first;
466 float angle = random_float(0, 2 *
M_PI);
467 float distance = random_float(1.2 * grape_radius, 1.3 * grape_radius);
470 helios::vec3 new_center(reference_center.
x + distance * cos(angle), reference_center.
y + distance * sin(angle), random_float(z - 0.5f * z_step, z + 0.5f * z_step));
473 float new_center_distance = std::sqrt(new_center.x * new_center.x + new_center.y * new_center.y);
474 if (new_center_distance > taper_radius) {
480 bool collision =
false;
481 for (
const auto &grape: grapes) {
482 if (spheres_overlap(new_center, grape_radius, grape.first, grape.second)) {
490 grapes.push_back({new_center, grape_radius});
498 std::vector<uint> UUIDs;
499 for (
const auto &grape: grapes) {
501 std::vector<uint> UUIDs_tmp = context_ptr->
addSphere(10, grape.first, grape.second,
make_RGBcolor(0.053, 0.076, 0.098));
502 UUIDs.insert(UUIDs.end(), UUIDs_tmp.begin(), UUIDs_tmp.end());
519void GrapevinePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
522 if (shoot_node_index >= 2) {
523 phytomer->setFloralBudState(BUD_DEAD);
525 if (phytomer->rank >= 1 && shoot_node_index >= 8) {
526 phytomer->setVegetativeBudState(BUD_DEAD);
528 if (phytomer->rank >= 2) {
529 phytomer->setVegetativeBudState(BUD_DEAD);
530 phytomer->setFloralBudState(BUD_DEAD);
549 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/MaizeTassel.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
555 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/MaizeEar.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
559void MaizePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
563 if (shoot_node_index <= 5) {
564 scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
565 phytomer->scaleInternodeMaxLength(scale);
566 }
else if (shoot_node_index >= phytomer->shoot_index.z - 5) {
567 scale = fmin(1.f, 0.65 + 0.35 *
float(phytomer->shoot_index.z - shoot_node_index) / 3.f);
570 phytomer->scaleLeafPrototypeScale(scale);
572 if (shoot_node_index > 8 && shoot_node_index < 12) {
573 phytomer->phytomer_parameters.inflorescence.flowers_per_peduncle = 1;
574 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeEarPrototype;
575 phytomer->phytomer_parameters.inflorescence.fruit_prototype_scale = 0.2;
576 phytomer->phytomer_parameters.peduncle.length = 0.05f;
577 phytomer->phytomer_parameters.peduncle.radius = 0.01;
578 phytomer->phytomer_parameters.peduncle.pitch = 5;
579 phytomer->setFloralBudState(BUD_ACTIVE);
581 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeTasselPrototype;
582 phytomer->setFloralBudState(BUD_DEAD);
590 std::vector<uint> UUIDs_upper =
592 std::vector<uint> UUIDs_lower =
596 UUIDs_upper.insert(UUIDs_upper.end(), UUIDs_lower.begin(), UUIDs_lower.end());
602 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/OliveFruit.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
610 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/OliveFlower_open.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
615void OlivePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
618void OlivePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
620 if (phytomer->isdormant) {
621 if (phytomer->shoot_index.x < phytomer->shoot_index.y - 8) {
622 phytomer->setFloralBudState(BUD_DEAD);
628 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/PistachioNut.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
634 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/OliveFlower_open.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
639void PistachioPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
642 if (shoot_node_index == 0) {
643 phytomer->setVegetativeBudState(BUD_DEAD);
644 phytomer->setFloralBudState(BUD_DEAD);
648void PistachioPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
650 if (phytomer->isdormant) {
651 if (phytomer->shoot_index.x <= phytomer->shoot_index.y - 4) {
652 phytomer->setFloralBudState(BUD_DORMANT);
658 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/PuncturevineFlower.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
664 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/RedbudFlower_open.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
669 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/RedbudPod.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
673void RedbudPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
676void RedbudPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
679 if (phytomer->isdormant) {
680 int Nchild_shoots =
randu(2, 4);
681 if (phytomer->shoot_index.x < phytomer->shoot_index.y - Nchild_shoots) {
682 phytomer->setVegetativeBudState(BUD_DEAD);
684 phytomer->setFloralBudState(BUD_DEAD);
690 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/RiceGrain.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
695void RicePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
698 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
699 phytomer->scaleLeafPrototypeScale(scale);
702 phytomer->scaleInternodeMaxLength(scale);
705void ButterLettucePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
707 float fact = float(shoot_max_nodes - shoot_node_index) / float(shoot_max_nodes);
714 phytomer->rotateLeaf(0, 0, make_AxisRotation(-
deg2rad(60) * fact, 0, 0));
719 if (subdivisions <= 1) {
723 float panicle_height = 1;
724 float panicle_width = 0.08;
725 float width_seed = 0.08;
726 float height_seed = 0.25;
727 float seed_tilt = 50;
730 std::string seed_texture_file =
"plugins/plantarchitecture/assets/textures/SorghumSeed.jpeg";
731 RGBcolor stem_color(0.45, 0.55, 0.42);
733 std::vector<uint> UUIDs;
735 panicle_height -= 0.8 * height_seed;
737 std::vector<vec3> nodes_panicle;
738 std::vector<float> radius_panicle;
740 for (
int n = 0; n < subdivisions; n++) {
745 z = 0.5f * height_seed / float(subdivisions - 1);
746 }
else if (n == subdivisions - 1) {
747 z = (subdivisions - 1.5f) * height_seed /
float(subdivisions - 1);
749 z = n * height_seed / float(subdivisions - 1);
752 float angle = float(n) *
M_PI / float(subdivisions - 1);
753 float dr = std::fmax(0.f, 0.5f * width_seed * sin(angle));
755 nodes_panicle.push_back(
make_vec3(x, y, z));
756 radius_panicle.push_back(dr);
759 std::vector<uint> UUIDs_seed_ptype = context_ptr->
addTube(subdivisions, nodes_panicle, radius_panicle, seed_texture_file.c_str());
761 int Ntheta = ceil(6.f * panicle_height / height_seed);
762 int Nphi = ceil(2.f *
M_PI * panicle_width / width_seed);
764 for (
int j = 0; j < Nphi; j++) {
765 for (
int i = 0; i < Ntheta; i++) {
767 if (i == 0 && j == 0) {
771 std::vector<uint> UUIDs_copy = context_ptr->
copyPrimitive(UUIDs_seed_ptype);
774 float phi = 2.f *
M_PI * float(j + 0.5f *
float(i % 2)) / float(Nphi);
775 float theta = acos(1 - 2 *
float(i +
float(j) /
float(Nphi)) /
float(Ntheta));
776 float x = sin(theta) * cos(phi);
777 float y = sin(theta) * sin(phi);
778 float z = 0.5f + 0.5f * cos(theta);
780 x *= 0.5f * panicle_width;
781 y *= 0.5f * panicle_width;
784 float tilt = -
deg2rad(seed_tilt) * sqrtf(1.f - z / panicle_height);
790 UUIDs.insert(UUIDs.end(), UUIDs_copy.begin(), UUIDs_copy.end());
796 std::vector<uint> UUIDs_sphere = context_ptr->
addSphere(10,
make_vec3(0, 0, 0.5 * panicle_height), 0.5f, seed_texture_file.c_str());
798 UUIDs.insert(UUIDs.end(), UUIDs_sphere.begin(), UUIDs_sphere.end());
807void SorghumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
810 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
811 phytomer->scaleLeafPrototypeScale(scale);
814 phytomer->scaleInternodeMaxLength(scale);
818 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/SoybeanPod.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
824 std::vector<uint> UUIDs;
825 if (flower_is_open) {
826 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/SoybeanFlower_open_white.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
828 UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/BeanFlower_closed_white.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
834void SoybeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
836 if (shoot_node_index > 5 || phytomer->rank > 1) {
837 phytomer->setVegetativeBudState(BUD_DEAD);
839 phytomer->setFloralBudState(BUD_DEAD);
843 float leaf_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 15.f);
844 phytomer->scaleLeafPrototypeScale(leaf_scale);
847 float inode_scale = fmin(1.f, 0.1 + 0.9 * plant_age / 15.f);
848 phytomer->scaleInternodeMaxLength(inode_scale);
852 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/StrawberryFlower.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
858 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/StrawberryFruit.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
864 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/TomatoFruit.obj",
make_vec3(0., 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
870 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/TomatoFlower.obj",
make_vec3(0.0, 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
875void TomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
877 if (shoot_node_index < 8 && phytomer->rank == 0) {
878 phytomer->setFloralBudState(BUD_DEAD);
880 if (phytomer->rank > 1) {
881 phytomer->setFloralBudState(BUD_DEAD);
882 phytomer->setVegetativeBudState(BUD_DEAD);
884 if (phytomer->rank > 1) {
885 phytomer->setFloralBudState(BUD_DEAD);
886 phytomer->setVegetativeBudState(BUD_DEAD);
890 float leaf_scale = fmin(1.f, 0.5 + 0.5 * plant_age / 10.f);
891 phytomer->scaleLeafPrototypeScale(leaf_scale);
894 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
895 phytomer->scaleInternodeMaxLength(inode_scale);
898void CherryTomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
900 if (shoot_node_index < 8 || phytomer->rank > 1) {
901 phytomer->setFloralBudState(BUD_DEAD);
902 phytomer->setVegetativeBudState(BUD_DEAD);
906 float leaf_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 15.f);
907 phytomer->scaleLeafPrototypeScale(leaf_scale);
910 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
911 phytomer->scaleInternodeMaxLength(inode_scale);
914void CherryTomatoPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
916 float pruning_height = 1.f;
917 float pruning_day = 101.f;
919 float plant_age = phytomer->parent_shoot_ptr->plantarchitecture_ptr->getPlantAge(phytomer->plantID);
921 if (phytomer->hasLeaf() && plant_age >= pruning_day) {
922 float height = phytomer->getInternodeNodePositions().at(0).z;
923 if (height < pruning_height) {
924 phytomer->removeLeaf();
930 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/WalnutHull.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
936 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/AlmondFlower.obj",
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
941void WalnutPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
944 if (shoot_node_index < 4) {
945 phytomer->setVegetativeBudState(BUD_DEAD);
946 phytomer->setFloralBudState(BUD_DEAD);
950void WalnutPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
954 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
"plugins/plantarchitecture/assets/obj/WheatSpike.obj",
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
959void WheatPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
962 float scale = std::fmin(1.f, 0.7f + 0.3f *
float(shoot_node_index) / 5.f);
963 phytomer->scaleLeafPrototypeScale(scale);
966 phytomer->scaleInternodeMaxLength(scale);