1.3.49
 
Loading...
Searching...
No Matches
PlantLibrary.cpp
Go to the documentation of this file.
1
16#include "CollisionDetection.h"
17#include "PlantArchitecture.h"
18
19using namespace helios;
20
21void PlantArchitecture::initializePlantModelRegistrations() {
22 // Register all available plant models
23 registerPlantModel("almond", [this]() { initializeAlmondTreeShoots(); }, [this](const helios::vec3 &pos) { return buildAlmondTree(pos); });
24
25 registerPlantModel("apple", [this]() { initializeAppleTreeShoots(); }, [this](const helios::vec3 &pos) { return buildAppleTree(pos); });
26
27 registerPlantModel("asparagus", [this]() { initializeAsparagusShoots(); }, [this](const helios::vec3 &pos) { return buildAsparagusPlant(pos); });
28
29 registerPlantModel("bindweed", [this]() { initializeBindweedShoots(); }, [this](const helios::vec3 &pos) { return buildBindweedPlant(pos); });
30
31 registerPlantModel("bean", [this]() { initializeBeanShoots(); }, [this](const helios::vec3 &pos) { return buildBeanPlant(pos); });
32
33 registerPlantModel("capsicum", [this]() { initializeCapsicumShoots(); }, [this](const helios::vec3 &pos) { return buildCapsicumPlant(pos); });
34
35 registerPlantModel("cheeseweed", [this]() { initializeCheeseweedShoots(); }, [this](const helios::vec3 &pos) { return buildCheeseweedPlant(pos); });
36
37 registerPlantModel("cowpea", [this]() { initializeCowpeaShoots(); }, [this](const helios::vec3 &pos) { return buildCowpeaPlant(pos); });
38
39 registerPlantModel("grapevine_VSP", [this]() { initializeGrapevineVSPShoots(); }, [this](const helios::vec3 &pos) { return buildGrapevineVSP(pos); });
40
41 registerPlantModel("grapevine_Wye", [this]() { initializeGrapevineWyeShoots(); }, [this](const helios::vec3 &pos) { return buildGrapevineWye(pos); });
42
43 registerPlantModel("groundcherryweed", [this]() { initializeGroundCherryWeedShoots(); }, [this](const helios::vec3 &pos) { return buildGroundCherryWeedPlant(pos); });
44
45 registerPlantModel("maize", [this]() { initializeMaizeShoots(); }, [this](const helios::vec3 &pos) { return buildMaizePlant(pos); });
46
47 registerPlantModel("olive", [this]() { initializeOliveTreeShoots(); }, [this](const helios::vec3 &pos) { return buildOliveTree(pos); });
48
49 registerPlantModel("pistachio", [this]() { initializePistachioTreeShoots(); }, [this](const helios::vec3 &pos) { return buildPistachioTree(pos); });
50
51 registerPlantModel("puncturevine", [this]() { initializePuncturevineShoots(); }, [this](const helios::vec3 &pos) { return buildPuncturevinePlant(pos); });
52
53 registerPlantModel("easternredbud", [this]() { initializeEasternRedbudShoots(); }, [this](const helios::vec3 &pos) { return buildEasternRedbudPlant(pos); });
54
55 registerPlantModel("rice", [this]() { initializeRiceShoots(); }, [this](const helios::vec3 &pos) { return buildRicePlant(pos); });
56
57 registerPlantModel("butterlettuce", [this]() { initializeButterLettuceShoots(); }, [this](const helios::vec3 &pos) { return buildButterLettucePlant(pos); });
58
59 registerPlantModel("sorghum", [this]() { initializeSorghumShoots(); }, [this](const helios::vec3 &pos) { return buildSorghumPlant(pos); });
60
61 registerPlantModel("soybean", [this]() { initializeSoybeanShoots(); }, [this](const helios::vec3 &pos) { return buildSoybeanPlant(pos); });
62
63 registerPlantModel("strawberry", [this]() { initializeStrawberryShoots(); }, [this](const helios::vec3 &pos) { return buildStrawberryPlant(pos); });
64
65 registerPlantModel("sugarbeet", [this]() { initializeSugarbeetShoots(); }, [this](const helios::vec3 &pos) { return buildSugarbeetPlant(pos); });
66
67 registerPlantModel("tomato", [this]() { initializeTomatoShoots(); }, [this](const helios::vec3 &pos) { return buildTomatoPlant(pos); });
68
69 registerPlantModel("cherrytomato", [this]() { initializeCherryTomatoShoots(); }, [this](const helios::vec3 &pos) { return buildCherryTomatoPlant(pos); });
70
71 registerPlantModel("walnut", [this]() { initializeWalnutTreeShoots(); }, [this](const helios::vec3 &pos) { return buildWalnutTree(pos); });
72
73 registerPlantModel("wheat", [this]() { initializeWheatShoots(); }, [this](const helios::vec3 &pos) { return buildWheatPlant(pos); });
74}
75
76void PlantArchitecture::loadPlantModelFromLibrary(const std::string &plant_label) {
77
78 current_plant_model = plant_label;
79 initializeDefaultShoots(plant_label);
80}
81
82std::vector<std::string> PlantArchitecture::getAvailablePlantModels() const {
83 std::vector<std::string> models;
84 models.reserve(shoot_initializers.size());
85 for (const auto &pair: shoot_initializers) {
86 models.push_back(pair.first);
87 }
88 return models;
89}
90
92
93 if (current_plant_model.empty()) {
94 helios_runtime_error("ERROR (PlantArchitecture::buildPlantInstanceFromLibrary): current plant model has not been initialized from library. You must call loadPlantModelFromLibrary() first.");
95 }
96
97 // Find the plant builder function
98 auto builder_it = plant_builders.find(current_plant_model);
99 if (builder_it == plant_builders.end()) {
100 helios_runtime_error("ERROR (PlantArchitecture::buildPlantInstanceFromLibrary): plant label of " + current_plant_model + " does not exist in the library.");
101 }
102
103 // Call the builder function
104 uint plantID = builder_it->second(base_position);
105
106 plant_instances.at(plantID).plant_name = current_plant_model;
107
108 // Register plant with per-tree BVH collision detection if enabled
109 if (collision_detection_enabled && collision_detection_ptr != nullptr && collision_detection_ptr->isTreeBasedBVHEnabled()) {
110 std::vector<uint> plant_primitives = getPlantCollisionRelevantObjectIDs(plantID);
111 if (!plant_primitives.empty()) {
112 collision_detection_ptr->registerTree(plantID, plant_primitives);
113 }
114 }
115
116 if (age > 0) {
117 advanceTime(plantID, age);
118 }
119
120 return plantID;
121}
122
124
125 if (shoot_types.find(shoot_type_label) == shoot_types.end()) {
126 helios_runtime_error("ERROR (PlantArchitecture::getCurrentShootParameters): shoot type label of " + shoot_type_label + " does not exist in the current shoot parameters.");
127 }
128
129 return shoot_types.at(shoot_type_label);
130}
131
132std::map<std::string, ShootParameters> PlantArchitecture::getCurrentShootParameters() {
133 if (shoot_types.empty()) {
134 std::cerr
135 << "WARNING (PlantArchitecture::getCurrentShootParameters): No plant models have been loaded. You need to first load a plant model from the library (see loadPlantModelFromLibrary()) or manually add shoot parameters (see updateCurrentShootParameters())."
136 << std::endl;
137 }
138 return shoot_types;
139}
140
141std::map<std::string, PhytomerParameters> PlantArchitecture::getCurrentPhytomerParameters() {
142 if (shoot_types.empty()) {
143 std::cerr
144 << "WARNING (PlantArchitecture::getCurrentPhytomerParameters): No plant models have been loaded. You need to first load a plant model from the library (see loadPlantModelFromLibrary()) or manually add shoot parameters (see updateCurrentShootParameters())."
145 << std::endl;
146 }
147 std::map<std::string, PhytomerParameters> phytomer_parameters;
148 for (const auto &type: shoot_types) {
149 phytomer_parameters[type.first] = type.second.phytomer_parameters;
150 }
151 return phytomer_parameters;
152}
153
154void PlantArchitecture::updateCurrentShootParameters(const std::string &shoot_type_label, const ShootParameters &params) {
155 shoot_types[shoot_type_label] = params;
156}
157
158void PlantArchitecture::updateCurrentShootParameters(const std::map<std::string, ShootParameters> &params) {
159 shoot_types = params;
160}
161
162void PlantArchitecture::initializeDefaultShoots(const std::string &plant_label) {
163
164 // Find the shoot initializer function
165 auto init_it = shoot_initializers.find(plant_label);
166 if (init_it == shoot_initializers.end()) {
167 helios_runtime_error("ERROR (PlantArchitecture::loadPlantModelFromLibrary): plant label of " + plant_label + " does not exist in the library.");
168 }
169
170 // Call the initializer function
171 init_it->second();
172}
173
174void PlantArchitecture::registerPlantModel(const std::string &name, std::function<void()> shoot_init, std::function<uint(const helios::vec3 &)> plant_build) {
175 shoot_initializers[name] = shoot_init;
176 plant_builders[name] = plant_build;
177}
178
179void PlantArchitecture::initializeAlmondTreeShoots() {
180
181 // ---- Leaf Prototype ---- //
182
183 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
184 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/AlmondLeaf.png";
185 leaf_prototype.leaf_aspect_ratio = 0.33f;
186 leaf_prototype.midrib_fold_fraction = 0.1f;
187 leaf_prototype.longitudinal_curvature = 0.05;
188 leaf_prototype.lateral_curvature = 0.1f;
189 leaf_prototype.subdivisions = 1;
190 leaf_prototype.unique_prototypes = 1;
191
192 // ---- Phytomer Parameters ---- //
193
194 PhytomerParameters phytomer_parameters_almond(context_ptr->getRandomGenerator());
195
196 phytomer_parameters_almond.internode.pitch = 3;
197 phytomer_parameters_almond.internode.phyllotactic_angle.uniformDistribution(120, 160);
198 phytomer_parameters_almond.internode.radius_initial = 0.002;
199 phytomer_parameters_almond.internode.length_segments = 1;
200 phytomer_parameters_almond.internode.image_texture = "plugins/plantarchitecture/assets/textures/AlmondBark.jpg";
201 phytomer_parameters_almond.internode.max_floral_buds_per_petiole = 1; //
202
203 phytomer_parameters_almond.petiole.petioles_per_internode = 1;
204 phytomer_parameters_almond.petiole.pitch.uniformDistribution(-145, -90);
205 phytomer_parameters_almond.petiole.taper = 0.1;
206 phytomer_parameters_almond.petiole.curvature = 0;
207 phytomer_parameters_almond.petiole.length = 0.04;
208 phytomer_parameters_almond.petiole.radius = 0.0005;
209 phytomer_parameters_almond.petiole.length_segments = 1;
210 phytomer_parameters_almond.petiole.radial_subdivisions = 3;
211 phytomer_parameters_almond.petiole.color = make_RGBcolor(0.61, 0.5, 0.24);
212
213 phytomer_parameters_almond.leaf.leaves_per_petiole = 1;
214 phytomer_parameters_almond.leaf.roll.uniformDistribution(-10, 10);
215 phytomer_parameters_almond.leaf.prototype_scale = 0.08;
216 phytomer_parameters_almond.leaf.prototype = leaf_prototype;
217
218 phytomer_parameters_almond.peduncle.length = 0.002;
219 phytomer_parameters_almond.peduncle.radius = 0.0005;
220 phytomer_parameters_almond.peduncle.pitch = 80;
221 phytomer_parameters_almond.peduncle.roll = 90;
222 phytomer_parameters_almond.peduncle.length_segments = 1;
223 phytomer_parameters_almond.petiole.radial_subdivisions = 3;
224
225 phytomer_parameters_almond.inflorescence.flowers_per_peduncle = 1;
226 phytomer_parameters_almond.inflorescence.pitch = 0;
227 phytomer_parameters_almond.inflorescence.roll = 0;
228 phytomer_parameters_almond.inflorescence.flower_prototype_scale = 0.04;
229 phytomer_parameters_almond.inflorescence.flower_prototype_function = AlmondFlowerPrototype;
230 phytomer_parameters_almond.inflorescence.fruit_prototype_scale = 0.04;
231 phytomer_parameters_almond.inflorescence.fruit_prototype_function = AlmondFruitPrototype;
232
233 // ---- Shoot Parameters ---- //
234
235 // Trunk
236 ShootParameters shoot_parameters_trunk(context_ptr->getRandomGenerator());
237 shoot_parameters_trunk.phytomer_parameters = phytomer_parameters_almond;
238 shoot_parameters_trunk.phytomer_parameters.internode.pitch = 0;
239 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
240 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.005;
241 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 24;
242 shoot_parameters_trunk.max_nodes = 20;
243 shoot_parameters_trunk.girth_area_factor = 10.f;
244 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
245 shoot_parameters_trunk.vegetative_bud_break_time = 0;
246 shoot_parameters_trunk.tortuosity = 1;
247 shoot_parameters_trunk.internode_length_max = 0.04;
248 shoot_parameters_trunk.internode_length_decay_rate = 0;
249 shoot_parameters_trunk.defineChildShootTypes({"scaffold"}, {1});
250
251 // Proleptic shoots
252 ShootParameters shoot_parameters_proleptic(context_ptr->getRandomGenerator());
253 shoot_parameters_proleptic.phytomer_parameters = phytomer_parameters_almond;
254 shoot_parameters_proleptic.phytomer_parameters.internode.color = make_RGBcolor(0.3, 0.2, 0.2);
255 shoot_parameters_proleptic.phytomer_parameters.internode.radial_subdivisions = 5;
256 shoot_parameters_proleptic.phytomer_parameters.phytomer_creation_function = AlmondPhytomerCreationFunction;
257 shoot_parameters_proleptic.phytomer_parameters.phytomer_callback_function = AlmondPhytomerCallbackFunction;
258 shoot_parameters_proleptic.max_nodes = 20;
259 shoot_parameters_proleptic.max_nodes_per_season = 15;
260 shoot_parameters_proleptic.phyllochron_min = 1;
261 shoot_parameters_proleptic.elongation_rate_max = 0.3;
262 shoot_parameters_proleptic.girth_area_factor = 8.f;
263 shoot_parameters_proleptic.vegetative_bud_break_probability_min = 0.15;
264 shoot_parameters_proleptic.vegetative_bud_break_probability_decay_rate = 0.6;
265 shoot_parameters_proleptic.vegetative_bud_break_time = 0;
266 shoot_parameters_proleptic.gravitropic_curvature = 200;
267 shoot_parameters_proleptic.tortuosity = 3;
268 shoot_parameters_proleptic.insertion_angle_tip.uniformDistribution(25, 30);
269 shoot_parameters_proleptic.insertion_angle_decay_rate = 15;
270 shoot_parameters_proleptic.internode_length_max = 0.02;
271 shoot_parameters_proleptic.internode_length_min = 0.002;
272 shoot_parameters_proleptic.internode_length_decay_rate = 0.002;
273 shoot_parameters_proleptic.fruit_set_probability = 0.4;
274 shoot_parameters_proleptic.flower_bud_break_probability = 0.3;
275 shoot_parameters_proleptic.max_terminal_floral_buds = 3;
276 shoot_parameters_proleptic.flowers_require_dormancy = true;
277 shoot_parameters_proleptic.growth_requires_dormancy = true;
278 shoot_parameters_proleptic.determinate_shoot_growth = false;
279 shoot_parameters_proleptic.defineChildShootTypes({"proleptic", "sylleptic"}, {1.0, 0.});
280
281 // Sylleptic shoots
282 ShootParameters shoot_parameters_sylleptic = shoot_parameters_proleptic;
283 // shoot_parameters_sylleptic.phytomer_parameters.internode.color = RGB::red;
284 shoot_parameters_sylleptic.phytomer_parameters.internode.image_texture = "";
285 shoot_parameters_sylleptic.phytomer_parameters.leaf.prototype_scale = 0.12;
286 shoot_parameters_sylleptic.phytomer_parameters.leaf.pitch.uniformDistribution(-45, -20);
287 shoot_parameters_sylleptic.insertion_angle_tip = 0;
288 shoot_parameters_sylleptic.insertion_angle_decay_rate = 0;
289 shoot_parameters_sylleptic.phyllochron_min = 1;
290 shoot_parameters_sylleptic.vegetative_bud_break_probability_min = 0.1;
291 shoot_parameters_sylleptic.gravitropic_curvature = 600;
292 shoot_parameters_sylleptic.internode_length_max = 0.02;
293 shoot_parameters_sylleptic.flowers_require_dormancy = true;
294 shoot_parameters_sylleptic.growth_requires_dormancy = true;
295 shoot_parameters_sylleptic.defineChildShootTypes({"proleptic"}, {1.0});
296
297 // Main scaffolds
298 ShootParameters shoot_parameters_scaffold = shoot_parameters_proleptic;
299 // shoot_parameters_scaffold.phytomer_parameters.internode.color = RGB::blue;
300 shoot_parameters_scaffold.phytomer_parameters.internode.radial_subdivisions = 10;
301 shoot_parameters_scaffold.max_nodes = 15;
302 shoot_parameters_scaffold.gravitropic_curvature = 150;
303 shoot_parameters_scaffold.internode_length_max = 0.02;
304 shoot_parameters_scaffold.tortuosity = 1.;
305 shoot_parameters_scaffold.defineChildShootTypes({"proleptic"}, {1.0});
306
307 defineShootType("trunk", shoot_parameters_trunk);
308 defineShootType("scaffold", shoot_parameters_scaffold);
309 defineShootType("proleptic", shoot_parameters_proleptic);
310 defineShootType("sylleptic", shoot_parameters_sylleptic);
311}
312
313uint PlantArchitecture::buildAlmondTree(const helios::vec3 &base_position) {
314
315 if (shoot_types.empty()) {
316 // automatically initialize almond tree shoots
317 initializeAlmondTreeShoots();
318 }
319
320 uint plantID = addPlantInstance(base_position, 0);
321
322 // enableEpicormicChildShoots(plantID,"sylleptic",0.001);
323
324 uint uID_trunk = addBaseStemShoot(plantID, 19, make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), 0.f * M_PI), 0.015, 0.03, 1.f, 1.f, 0, "trunk");
325 appendPhytomerToShoot(plantID, uID_trunk, shoot_types.at("trunk").phytomer_parameters, 0.01, 0.01, 1, 1);
326
327 plant_instances.at(plantID).shoot_tree.at(uID_trunk)->meristem_is_alive = false;
328
329 auto phytomers = plant_instances.at(plantID).shoot_tree.at(uID_trunk)->phytomers;
330 for (const auto &phytomer: phytomers) {
331 phytomer->removeLeaf();
332 phytomer->setVegetativeBudState(BUD_DEAD);
333 phytomer->setFloralBudState(BUD_DEAD);
334 }
335
336 uint Nscaffolds = 4; // context_ptr->randu(4,5);
337
338 for (int i = 0; i < Nscaffolds; i++) {
339 float pitch = context_ptr->randu(deg2rad(35), deg2rad(45));
340 uint uID_shoot = addChildShoot(plantID, uID_trunk, getShootNodeCount(plantID, uID_trunk) - i - 1, context_ptr->randu(7, 9), make_AxisRotation(pitch, (float(i) + context_ptr->randu(-0.2f, 0.2f)) / float(Nscaffolds) * 2 * M_PI, 0), 0.007, 0.06,
341 1.f, 1.f, 0.5, "scaffold", 0);
342 }
343
344 makePlantDormant(plantID);
345
346 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 20, 200, false);
347 plant_instances.at(plantID).max_age = 1825;
348
349 return plantID;
350}
351
352void PlantArchitecture::initializeAppleTreeShoots() {
353
354 // ---- Leaf Prototype ---- //
355
356 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
357 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/AppleLeaf.png";
358 leaf_prototype.leaf_aspect_ratio = 0.6f;
359 leaf_prototype.midrib_fold_fraction = 0.4f;
360 leaf_prototype.longitudinal_curvature = -0.3f;
361 leaf_prototype.lateral_curvature = 0.1f;
362 leaf_prototype.subdivisions = 3;
363 leaf_prototype.unique_prototypes = 1;
364
365 // ---- Phytomer Parameters ---- //
366
367 PhytomerParameters phytomer_parameters_apple(context_ptr->getRandomGenerator());
368
369 phytomer_parameters_apple.internode.pitch = 0;
370 phytomer_parameters_apple.internode.phyllotactic_angle.uniformDistribution(130, 145);
371 phytomer_parameters_apple.internode.radius_initial = 0.004;
372 phytomer_parameters_apple.internode.length_segments = 1;
373 phytomer_parameters_apple.internode.image_texture = "plugins/plantarchitecture/assets/textures/AppleBark.jpg";
374 phytomer_parameters_apple.internode.max_floral_buds_per_petiole = 1;
375
376 phytomer_parameters_apple.petiole.petioles_per_internode = 1;
377 phytomer_parameters_apple.petiole.pitch.uniformDistribution(-40, -25);
378 phytomer_parameters_apple.petiole.taper = 0.1;
379 phytomer_parameters_apple.petiole.curvature = 0;
380 phytomer_parameters_apple.petiole.length = 0.04;
381 phytomer_parameters_apple.petiole.radius = 0.00075;
382 phytomer_parameters_apple.petiole.length_segments = 1;
383 phytomer_parameters_apple.petiole.radial_subdivisions = 3;
384 phytomer_parameters_apple.petiole.color = make_RGBcolor(0.61, 0.5, 0.24);
385
386 phytomer_parameters_apple.leaf.leaves_per_petiole = 1;
387 phytomer_parameters_apple.leaf.prototype_scale = 0.12;
388 phytomer_parameters_apple.leaf.prototype = leaf_prototype;
389
390 phytomer_parameters_apple.peduncle.length = 0.04;
391 phytomer_parameters_apple.peduncle.radius = 0.001;
392 phytomer_parameters_apple.peduncle.pitch = 90;
393 phytomer_parameters_apple.peduncle.roll = 90;
394 phytomer_parameters_apple.peduncle.length_segments = 1;
395
396 phytomer_parameters_apple.inflorescence.flowers_per_peduncle = 1;
397 phytomer_parameters_apple.inflorescence.pitch = 0;
398 phytomer_parameters_apple.inflorescence.roll = 0;
399 phytomer_parameters_apple.inflorescence.flower_prototype_scale = 0.03;
400 phytomer_parameters_apple.inflorescence.flower_prototype_function = AppleFlowerPrototype;
401 phytomer_parameters_apple.inflorescence.fruit_prototype_scale = 0.1;
402 phytomer_parameters_apple.inflorescence.fruit_prototype_function = AppleFruitPrototype;
403 phytomer_parameters_apple.inflorescence.fruit_gravity_factor_fraction = 0.5;
404
405 // ---- Shoot Parameters ---- //
406
407 // Trunk
408 ShootParameters shoot_parameters_trunk(context_ptr->getRandomGenerator());
409 shoot_parameters_trunk.phytomer_parameters = phytomer_parameters_apple;
410 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
411 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.01;
412 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 24;
413 shoot_parameters_trunk.max_nodes = 20;
414 shoot_parameters_trunk.girth_area_factor = 5.f;
415 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
416 shoot_parameters_trunk.vegetative_bud_break_time = 0;
417 shoot_parameters_trunk.tortuosity = 1;
418 shoot_parameters_trunk.internode_length_max = 0.05;
419 shoot_parameters_trunk.internode_length_decay_rate = 0;
420 shoot_parameters_trunk.defineChildShootTypes({"proleptic"}, {1});
421
422 // Proleptic shoots
423 ShootParameters shoot_parameters_proleptic(context_ptr->getRandomGenerator());
424 shoot_parameters_proleptic.phytomer_parameters = phytomer_parameters_apple;
425 shoot_parameters_proleptic.phytomer_parameters.internode.color = make_RGBcolor(0.3, 0.2, 0.2);
426 shoot_parameters_proleptic.phytomer_parameters.phytomer_creation_function = ApplePhytomerCreationFunction;
427 shoot_parameters_proleptic.max_nodes = 40;
428 shoot_parameters_proleptic.max_nodes_per_season = 20;
429 shoot_parameters_proleptic.phyllochron_min = 2.0;
430 shoot_parameters_proleptic.elongation_rate_max = 0.15;
431 shoot_parameters_proleptic.girth_area_factor = 7.f;
432 shoot_parameters_proleptic.vegetative_bud_break_probability_min = 0.1;
433 shoot_parameters_proleptic.vegetative_bud_break_probability_decay_rate = 0.4;
434 shoot_parameters_proleptic.vegetative_bud_break_time = 0;
435 shoot_parameters_proleptic.gravitropic_curvature.uniformDistribution(450, 500);
436 shoot_parameters_proleptic.tortuosity = 3;
437 shoot_parameters_proleptic.insertion_angle_tip.uniformDistribution(30, 40);
438 shoot_parameters_proleptic.insertion_angle_decay_rate = 20;
439 shoot_parameters_proleptic.internode_length_max = 0.04;
440 shoot_parameters_proleptic.internode_length_min = 0.01;
441 shoot_parameters_proleptic.internode_length_decay_rate = 0.004;
442 shoot_parameters_proleptic.fruit_set_probability = 0.3;
443 shoot_parameters_proleptic.flower_bud_break_probability = 0.3;
444 shoot_parameters_proleptic.max_terminal_floral_buds = 1;
445 shoot_parameters_proleptic.flowers_require_dormancy = true;
446 shoot_parameters_proleptic.growth_requires_dormancy = true;
447 shoot_parameters_proleptic.determinate_shoot_growth = false;
448 shoot_parameters_proleptic.defineChildShootTypes({"proleptic"}, {1.0});
449
450 defineShootType("trunk", shoot_parameters_trunk);
451 defineShootType("proleptic", shoot_parameters_proleptic);
452}
453
454uint PlantArchitecture::buildAppleTree(const helios::vec3 &base_position) {
455
456 if (shoot_types.empty()) {
457 // automatically initialize apple tree shoots
458 initializeAppleTreeShoots();
459 }
460
461 uint plantID = addPlantInstance(base_position, 0);
462
463 uint uID_trunk = addBaseStemShoot(plantID, 19, make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), 0.f * M_PI), 0.015, 0.04, 1.f, 1.f, 0, "trunk");
464 appendPhytomerToShoot(plantID, uID_trunk, shoot_types.at("trunk").phytomer_parameters, 0, 0.01, 1, 1);
465
466 plant_instances.at(plantID).shoot_tree.at(uID_trunk)->meristem_is_alive = false;
467
468 auto phytomers = plant_instances.at(plantID).shoot_tree.at(uID_trunk)->phytomers;
469 for (const auto &phytomer: phytomers) {
470 phytomer->removeLeaf();
471 phytomer->setVegetativeBudState(BUD_DEAD);
472 phytomer->setFloralBudState(BUD_DEAD);
473 }
474
475 uint Nscaffolds = 4; // context_ptr->randu(4,5);
476
477 for (int i = 0; i < Nscaffolds; i++) {
478 float pitch = context_ptr->randu(deg2rad(35), deg2rad(45));
479 uint uID_shoot = addChildShoot(plantID, uID_trunk, getShootNodeCount(plantID, uID_trunk) - i - 1, context_ptr->randu(7, 9), make_AxisRotation(pitch, (float(i) + context_ptr->randu(-0.2f, 0.2f)) / float(Nscaffolds) * 2 * M_PI, 0), 0.005, 0.04,
480 1.f, 1.f, 0.5, "proleptic", 0);
481 }
482
483 makePlantDormant(plantID);
484
485 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 30, 200, false);
486 plant_instances.at(plantID).max_age = 1460;
487
488 return plantID;
489}
490
491void PlantArchitecture::initializeAsparagusShoots() {
492
493 // ---- Phytomer Parameters ---- //
494
495 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
496
497 phytomer_parameters.internode.pitch = 1;
498 phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(127.5, 147.5);
499 phytomer_parameters.internode.radius_initial = 0.00025;
500 phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
501 phytomer_parameters.internode.max_vegetative_buds_per_petiole = 1;
502 phytomer_parameters.internode.color = RGB::forestgreen;
503 phytomer_parameters.internode.length_segments = 2;
504
505 phytomer_parameters.petiole.petioles_per_internode = 1;
506 phytomer_parameters.petiole.pitch = 90;
507 phytomer_parameters.petiole.radius = 0.0001;
508 phytomer_parameters.petiole.length = 0.0005;
509 phytomer_parameters.petiole.taper = 0.5;
510 phytomer_parameters.petiole.curvature = 0;
511 phytomer_parameters.petiole.color = phytomer_parameters.internode.color;
512 phytomer_parameters.petiole.length_segments = 1;
513 phytomer_parameters.petiole.radial_subdivisions = 5;
514
515 phytomer_parameters.leaf.leaves_per_petiole = 5;
516 phytomer_parameters.leaf.pitch.normalDistribution(-5, 30);
517 phytomer_parameters.leaf.yaw = 30;
518 phytomer_parameters.leaf.roll = 0;
519 phytomer_parameters.leaf.leaflet_offset = 0;
520 phytomer_parameters.leaf.leaflet_scale = 0.9;
521 phytomer_parameters.leaf.prototype.prototype_function = AsparagusLeafPrototype;
522 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.018, 0.02);
523 // phytomer_parameters.leaf.subdivisions = 6;
524
525 phytomer_parameters.peduncle.length = 0.17;
526 phytomer_parameters.peduncle.radius = 0.0015;
527 phytomer_parameters.peduncle.pitch.uniformDistribution(0, 30);
528 phytomer_parameters.peduncle.roll = 90;
529 phytomer_parameters.peduncle.curvature.uniformDistribution(50, 250);
530 phytomer_parameters.peduncle.length_segments = 6;
531 phytomer_parameters.peduncle.radial_subdivisions = 6;
532
533 phytomer_parameters.inflorescence.flowers_per_peduncle.uniformDistribution(1, 3);
534 phytomer_parameters.inflorescence.flower_offset = 0.;
535 phytomer_parameters.inflorescence.pitch.uniformDistribution(50, 70);
536 phytomer_parameters.inflorescence.roll.uniformDistribution(-20, 20);
537 phytomer_parameters.inflorescence.flower_prototype_scale = 0.015;
538 phytomer_parameters.inflorescence.fruit_prototype_scale.uniformDistribution(0.02, 0.025);
539 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction.uniformDistribution(0., 0.5);
540
541 // ---- Shoot Parameters ---- //
542
543 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
544 shoot_parameters.phytomer_parameters = phytomer_parameters;
545 shoot_parameters.phytomer_parameters.phytomer_creation_function = AsparagusPhytomerCreationFunction;
546
547 shoot_parameters.max_nodes = 20;
548 shoot_parameters.insertion_angle_tip.uniformDistribution(40, 70);
549 // shoot_parameters.child_insertion_angle_decay_rate = 0; (default)
550 shoot_parameters.internode_length_max = 0.015;
551 // shoot_parameters.child_internode_length_min = 0.0; (default)
552 // shoot_parameters.child_internode_length_decay_rate = 0; (default)
553 shoot_parameters.base_roll = 90;
554 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
555 shoot_parameters.gravitropic_curvature = -200;
556
557 shoot_parameters.phyllochron_min = 1;
558 shoot_parameters.elongation_rate_max = 0.15;
559 // shoot_parameters.girth_growth_rate = 0.00005;
560 shoot_parameters.girth_area_factor = 30;
561 shoot_parameters.vegetative_bud_break_time = 5;
562 shoot_parameters.vegetative_bud_break_probability_min = 0.25;
563 // shoot_parameters.max_terminal_floral_buds = 0; (default)
564 // shoot_parameters.flower_bud_break_probability.uniformDistribution(0.1, 0.2);
565 shoot_parameters.fruit_set_probability = 0.;
566 // shoot_parameters.flowers_require_dormancy = false; (default)
567 // shoot_parameters.growth_requires_dormancy = false; (default)
568 // shoot_parameters.determinate_shoot_growth = true; (default)
569
570 shoot_parameters.defineChildShootTypes({"main"}, {1.0});
571
572 defineShootType("main", shoot_parameters);
573}
574
575uint PlantArchitecture::buildAsparagusPlant(const helios::vec3 &base_position) {
576
577 if (shoot_types.empty()) {
578 // automatically initialize asparagus plant shoots
579 initializeAsparagusShoots();
580 }
581
582 uint plantID = addPlantInstance(base_position, 0);
583
584 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(0, 0.f, 0.f), 0.0003, 0.015, 1, 0.1, 0.1, "main");
585
586 breakPlantDormancy(plantID);
587
588 setPlantPhenologicalThresholds(plantID, 0, -1, -1, -1, 5, 100, false);
589
590 plant_instances.at(plantID).max_age = 20;
591
592 return plantID;
593}
594
595void PlantArchitecture::initializeBindweedShoots() {
596
597 // ---- Phytomer Parameters ---- //
598
599 PhytomerParameters phytomer_parameters_bindweed(context_ptr->getRandomGenerator());
600
601 phytomer_parameters_bindweed.internode.pitch.uniformDistribution(0, 15);
602 phytomer_parameters_bindweed.internode.phyllotactic_angle = 180.f;
603 phytomer_parameters_bindweed.internode.radius_initial = 0.0012;
604 phytomer_parameters_bindweed.internode.color = make_RGBcolor(0.3, 0.38, 0.21);
605 phytomer_parameters_bindweed.internode.length_segments = 1;
606
607 phytomer_parameters_bindweed.petiole.petioles_per_internode = 1;
608 phytomer_parameters_bindweed.petiole.pitch.uniformDistribution(80, 100);
609 phytomer_parameters_bindweed.petiole.radius = 0.001;
610 phytomer_parameters_bindweed.petiole.length = 0.006;
611 phytomer_parameters_bindweed.petiole.taper = 0;
612 phytomer_parameters_bindweed.petiole.curvature = 0;
613 phytomer_parameters_bindweed.petiole.color = phytomer_parameters_bindweed.internode.color;
614 phytomer_parameters_bindweed.petiole.length_segments = 1;
615
616 phytomer_parameters_bindweed.leaf.leaves_per_petiole = 1;
617 phytomer_parameters_bindweed.leaf.pitch.uniformDistribution(5, 30);
618 phytomer_parameters_bindweed.leaf.yaw = 0;
619 phytomer_parameters_bindweed.leaf.roll = 90;
620 phytomer_parameters_bindweed.leaf.prototype_scale = 0.05;
621 phytomer_parameters_bindweed.leaf.prototype.OBJ_model_file = "plugins/plantarchitecture/assets/obj/BindweedLeaf.obj";
622
623 phytomer_parameters_bindweed.peduncle.length = 0.01;
624 phytomer_parameters_bindweed.peduncle.radius = 0.0005;
625 phytomer_parameters_bindweed.peduncle.color = phytomer_parameters_bindweed.internode.color;
626
627 phytomer_parameters_bindweed.inflorescence.flowers_per_peduncle = 1;
628 phytomer_parameters_bindweed.inflorescence.pitch = -90.f;
629 phytomer_parameters_bindweed.inflorescence.flower_prototype_function = BindweedFlowerPrototype;
630 phytomer_parameters_bindweed.inflorescence.flower_prototype_scale = 0.045;
631
632 // ---- Shoot Parameters ---- //
633
634 ShootParameters shoot_parameters_primary(context_ptr->getRandomGenerator());
635 shoot_parameters_primary.phytomer_parameters = phytomer_parameters_bindweed;
636 shoot_parameters_primary.vegetative_bud_break_probability_min = 0.1;
637 shoot_parameters_primary.vegetative_bud_break_probability_decay_rate = -1.;
638 shoot_parameters_primary.vegetative_bud_break_time = 10;
639 shoot_parameters_primary.base_roll = 90;
640 shoot_parameters_primary.phyllochron_min = 1;
641 shoot_parameters_primary.elongation_rate_max = 0.25;
642 shoot_parameters_primary.girth_area_factor = 0;
643 shoot_parameters_primary.internode_length_max = 0.03;
644 shoot_parameters_primary.internode_length_decay_rate = 0;
645 shoot_parameters_primary.insertion_angle_tip.uniformDistribution(50, 80);
646 shoot_parameters_primary.flowers_require_dormancy = false;
647 shoot_parameters_primary.growth_requires_dormancy = false;
648 shoot_parameters_primary.flower_bud_break_probability = 0.2;
649 shoot_parameters_primary.determinate_shoot_growth = false;
650 shoot_parameters_primary.max_nodes = 15;
651 shoot_parameters_primary.gravitropic_curvature = 40;
652 shoot_parameters_primary.tortuosity = 0;
653 shoot_parameters_primary.defineChildShootTypes({"secondary_bindweed"}, {1.f});
654
655 ShootParameters shoot_parameters_base = shoot_parameters_primary;
656 shoot_parameters_base.phytomer_parameters = phytomer_parameters_bindweed;
657 shoot_parameters_base.phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(137.5 - 10, 137.5 + 10);
658 shoot_parameters_base.phytomer_parameters.internode.pitch = 0;
659 shoot_parameters_base.phytomer_parameters.petiole.pitch = 0;
660 shoot_parameters_base.vegetative_bud_break_probability_min = 1.0;
661 shoot_parameters_base.vegetative_bud_break_time = 2;
662 shoot_parameters_base.phyllochron_min = 2;
663 shoot_parameters_base.elongation_rate_max = 0.15;
664 shoot_parameters_base.girth_area_factor = 0.f;
665 shoot_parameters_base.gravitropic_curvature = 0;
666 shoot_parameters_base.internode_length_max = 0.01;
667 shoot_parameters_base.internode_length_decay_rate = 0;
668 shoot_parameters_base.insertion_angle_tip = 95;
669 shoot_parameters_base.insertion_angle_decay_rate = 0;
670 shoot_parameters_base.flowers_require_dormancy = false;
671 shoot_parameters_base.growth_requires_dormancy = false;
672 shoot_parameters_base.flower_bud_break_probability = 0.0;
673 shoot_parameters_base.max_nodes.uniformDistribution(3, 5);
674 shoot_parameters_base.defineChildShootTypes({"primary_bindweed"}, {1.f});
675
676 ShootParameters shoot_parameters_children = shoot_parameters_primary;
677 shoot_parameters_children.base_roll = 0;
678
679 defineShootType("base_bindweed", shoot_parameters_base);
680 defineShootType("primary_bindweed", shoot_parameters_primary);
681 defineShootType("secondary_bindweed", shoot_parameters_children);
682}
683
684uint PlantArchitecture::buildBindweedPlant(const helios::vec3 &base_position) {
685
686 if (shoot_types.empty()) {
687 // automatically initialize bindweed plant shoots
688 initializeBindweedShoots();
689 }
690
691 uint plantID = addPlantInstance(base_position, 0);
692
693 uint uID_stem = addBaseStemShoot(plantID, 3, make_AxisRotation(0, 0.f, 0.f), 0.001, 0.001, 1, 1, 0, "base_bindweed");
694
695 breakPlantDormancy(plantID);
696
697 setPlantPhenologicalThresholds(plantID, 0, -1, 14, -1, -1, 1000, false);
698
699 plant_instances.at(plantID).max_age = 50;
700
701 return plantID;
702}
703
704void PlantArchitecture::initializeBeanShoots() {
705
706 // ---- Leaf Prototype ---- //
707
708 LeafPrototype leaf_prototype_trifoliate(context_ptr->getRandomGenerator());
709 leaf_prototype_trifoliate.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/BeanLeaf_tip.png";
710 leaf_prototype_trifoliate.leaf_texture_file[-1] = "plugins/plantarchitecture/assets/textures/BeanLeaf_left_centered.png";
711 leaf_prototype_trifoliate.leaf_texture_file[1] = "plugins/plantarchitecture/assets/textures/BeanLeaf_right_centered.png";
712 leaf_prototype_trifoliate.leaf_aspect_ratio = 1.f;
713 leaf_prototype_trifoliate.midrib_fold_fraction = 0.2;
714 leaf_prototype_trifoliate.longitudinal_curvature.uniformDistribution(-0.3f, -0.2f);
715 leaf_prototype_trifoliate.lateral_curvature = -1.f;
716 leaf_prototype_trifoliate.subdivisions = 6;
717 leaf_prototype_trifoliate.unique_prototypes = 5;
718 leaf_prototype_trifoliate.build_petiolule = true;
719
720 LeafPrototype leaf_prototype_unifoliate = leaf_prototype_trifoliate;
721 leaf_prototype_unifoliate.leaf_texture_file.clear();
722 leaf_prototype_unifoliate.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/BeanLeaf_unifoliate_centered.png";
723 leaf_prototype_unifoliate.unique_prototypes = 2;
724
725 // ---- Phytomer Parameters ---- //
726
727 PhytomerParameters phytomer_parameters_trifoliate(context_ptr->getRandomGenerator());
728
729 phytomer_parameters_trifoliate.internode.pitch = 20;
730 phytomer_parameters_trifoliate.internode.phyllotactic_angle.uniformDistribution(145, 215);
731 phytomer_parameters_trifoliate.internode.radius_initial = 0.001;
732 phytomer_parameters_trifoliate.internode.max_floral_buds_per_petiole = 1;
733 phytomer_parameters_trifoliate.internode.max_vegetative_buds_per_petiole = 1;
734 phytomer_parameters_trifoliate.internode.color = make_RGBcolor(0.2, 0.25, 0.05);
735 phytomer_parameters_trifoliate.internode.length_segments = 2;
736
737 phytomer_parameters_trifoliate.petiole.petioles_per_internode = 1;
738 phytomer_parameters_trifoliate.petiole.pitch.uniformDistribution(20, 50);
739 phytomer_parameters_trifoliate.petiole.radius = 0.0015;
740 phytomer_parameters_trifoliate.petiole.length.uniformDistribution(0.1, 0.14);
741 phytomer_parameters_trifoliate.petiole.taper = 0.;
742 phytomer_parameters_trifoliate.petiole.curvature.uniformDistribution(-100, 200);
743 phytomer_parameters_trifoliate.petiole.color = make_RGBcolor(0.28, 0.35, 0.07);
744 phytomer_parameters_trifoliate.petiole.length_segments = 5;
745 phytomer_parameters_trifoliate.petiole.radial_subdivisions = 6;
746
747 phytomer_parameters_trifoliate.leaf.leaves_per_petiole = 3;
748 phytomer_parameters_trifoliate.leaf.pitch.normalDistribution(0, 20);
749 phytomer_parameters_trifoliate.leaf.yaw = 10;
750 phytomer_parameters_trifoliate.leaf.roll = -15;
751 phytomer_parameters_trifoliate.leaf.leaflet_offset = 0.3;
752 phytomer_parameters_trifoliate.leaf.leaflet_scale = 0.9;
753 phytomer_parameters_trifoliate.leaf.prototype_scale.uniformDistribution(0.09, 0.11);
754 phytomer_parameters_trifoliate.leaf.prototype = leaf_prototype_trifoliate;
755
756 phytomer_parameters_trifoliate.peduncle.length = 0.04;
757 phytomer_parameters_trifoliate.peduncle.radius = 0.00075;
758 phytomer_parameters_trifoliate.peduncle.pitch.uniformDistribution(0, 40);
759 phytomer_parameters_trifoliate.peduncle.roll = 90;
760 phytomer_parameters_trifoliate.peduncle.curvature.uniformDistribution(-500, 500);
761 phytomer_parameters_trifoliate.peduncle.color = phytomer_parameters_trifoliate.petiole.color;
762 phytomer_parameters_trifoliate.peduncle.length_segments = 1;
763 phytomer_parameters_trifoliate.peduncle.radial_subdivisions = 6;
764
765 phytomer_parameters_trifoliate.inflorescence.flowers_per_peduncle.uniformDistribution(1, 4);
766 phytomer_parameters_trifoliate.inflorescence.flower_offset = 0.2;
767 phytomer_parameters_trifoliate.inflorescence.pitch.uniformDistribution(50, 70);
768 phytomer_parameters_trifoliate.inflorescence.roll.uniformDistribution(-20, 20);
769 phytomer_parameters_trifoliate.inflorescence.flower_prototype_scale = 0.03;
770 phytomer_parameters_trifoliate.inflorescence.flower_prototype_function = BeanFlowerPrototype;
771 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_scale.uniformDistribution(0.15, 0.2);
772 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_function = BeanFruitPrototype;
773 phytomer_parameters_trifoliate.inflorescence.fruit_gravity_factor_fraction.uniformDistribution(0.8, 1.0);
774
775 PhytomerParameters phytomer_parameters_unifoliate = phytomer_parameters_trifoliate;
776 phytomer_parameters_unifoliate.internode.pitch = 0;
777 phytomer_parameters_unifoliate.internode.max_vegetative_buds_per_petiole = 1;
778 phytomer_parameters_unifoliate.internode.max_floral_buds_per_petiole = 0;
779 phytomer_parameters_unifoliate.petiole.petioles_per_internode = 2;
780 phytomer_parameters_unifoliate.petiole.length = 0.0001;
781 phytomer_parameters_unifoliate.petiole.radius = 0.0004;
782 phytomer_parameters_unifoliate.petiole.pitch.uniformDistribution(50, 70);
783 phytomer_parameters_unifoliate.leaf.leaves_per_petiole = 1;
784 phytomer_parameters_unifoliate.leaf.prototype_scale = 0.04;
785 phytomer_parameters_unifoliate.leaf.pitch.uniformDistribution(-10, 10);
786 phytomer_parameters_unifoliate.leaf.prototype = leaf_prototype_unifoliate;
787
788 // ---- Shoot Parameters ---- //
789
790 ShootParameters shoot_parameters_trifoliate(context_ptr->getRandomGenerator());
791 shoot_parameters_trifoliate.phytomer_parameters = phytomer_parameters_trifoliate;
792 shoot_parameters_trifoliate.phytomer_parameters.phytomer_creation_function = BeanPhytomerCreationFunction;
793
794 shoot_parameters_trifoliate.max_nodes = 25;
795 shoot_parameters_trifoliate.insertion_angle_tip.uniformDistribution(40, 60);
796 // shoot_parameters_trifoliate.child_insertion_angle_decay_rate = 0; (default)
797 shoot_parameters_trifoliate.internode_length_max = 0.025;
798 // shoot_parameters_trifoliate.child_internode_length_min = 0.0; (default)
799 // shoot_parameters_trifoliate.child_internode_length_decay_rate = 0; (default)
800 shoot_parameters_trifoliate.base_roll = 90;
801 shoot_parameters_trifoliate.base_yaw.uniformDistribution(-20, 20);
802 shoot_parameters_trifoliate.gravitropic_curvature = 200;
803
804 shoot_parameters_trifoliate.phyllochron_min = 2;
805 shoot_parameters_trifoliate.elongation_rate_max = 0.1;
806 shoot_parameters_trifoliate.girth_area_factor = 1.5f;
807 shoot_parameters_trifoliate.vegetative_bud_break_time = 15;
808 shoot_parameters_trifoliate.vegetative_bud_break_probability_min = 0.1;
809 shoot_parameters_trifoliate.vegetative_bud_break_probability_decay_rate = -0.4;
810 // shoot_parameters_trifoliate.max_terminal_floral_buds = 0; (default)
811 shoot_parameters_trifoliate.flower_bud_break_probability.uniformDistribution(0.3, 0.4);
812 shoot_parameters_trifoliate.fruit_set_probability = 0.4;
813 // shoot_parameters_trifoliate.flowers_require_dormancy = false; (default)
814 // shoot_parameters_trifoliate.growth_requires_dormancy = false; (default)
815 // shoot_parameters_trifoliate.determinate_shoot_growth = true; (default)
816
817 shoot_parameters_trifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
818
819
820 ShootParameters shoot_parameters_unifoliate = shoot_parameters_trifoliate;
821 shoot_parameters_unifoliate.phytomer_parameters = phytomer_parameters_unifoliate;
822 shoot_parameters_unifoliate.phytomer_parameters.phytomer_creation_function = nullptr;
823 shoot_parameters_unifoliate.max_nodes = 1;
824 shoot_parameters_unifoliate.girth_area_factor = 1.f;
825 shoot_parameters_unifoliate.vegetative_bud_break_probability_min = 1.0;
826 shoot_parameters_unifoliate.flower_bud_break_probability = 0;
827 shoot_parameters_unifoliate.insertion_angle_tip = 50;
828 shoot_parameters_unifoliate.insertion_angle_decay_rate = 0;
829 shoot_parameters_unifoliate.vegetative_bud_break_time = 8;
830 shoot_parameters_unifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
831
832 defineShootType("unifoliate", shoot_parameters_unifoliate);
833 defineShootType("trifoliate", shoot_parameters_trifoliate);
834}
835
836uint PlantArchitecture::buildBeanPlant(const helios::vec3 &base_position) {
837
838 if (shoot_types.empty()) {
839 // automatically initialize bean plant shoots
840 initializeBeanShoots();
841 }
842
843 uint plantID = addPlantInstance(base_position, 0);
844
845 AxisRotation base_rotation = make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
846 uint uID_unifoliate = addBaseStemShoot(plantID, 1, base_rotation, 0.0005, 0.03, 0.01, 0.01, 0, "unifoliate");
847
848 appendShoot(plantID, uID_unifoliate, 1, make_AxisRotation(0, 0, 0.5f * M_PI), shoot_types.at("trifoliate").phytomer_parameters.internode.radius_initial.val(), shoot_types.at("trifoliate").internode_length_max.val(), 0.1, 0.1, 0, "trifoliate");
849
850 breakPlantDormancy(plantID);
851
852 setPlantPhenologicalThresholds(plantID, 0, 40, 5, 5, 30, 1000, false);
853
854 plant_instances.at(plantID).max_age = 365;
855
856 return plantID;
857}
858
859void PlantArchitecture::initializeCapsicumShoots() {
860
861 // ---- Leaf Prototype ---- //
862
863 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
864 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/CapsicumLeaf.png";
865 leaf_prototype.leaf_aspect_ratio = 0.45f;
866 leaf_prototype.midrib_fold_fraction = 0.1f;
867 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.15, -0.05f);
868 leaf_prototype.lateral_curvature = -0.15f;
869 leaf_prototype.wave_period = 0.35f;
870 leaf_prototype.wave_amplitude = 0.0f;
871 leaf_prototype.subdivisions = 5;
872 leaf_prototype.unique_prototypes = 5;
873
874 // ---- Phytomer Parameters ---- //
875
876 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
877
878 phytomer_parameters.internode.pitch = 10;
879 phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(137.5 - 10, 137.5 + 10);
880 phytomer_parameters.internode.radius_initial = 0.001;
881 phytomer_parameters.internode.color = make_RGBcolor(0.213, 0.270, 0.056);
882 phytomer_parameters.internode.length_segments = 1;
883
884 phytomer_parameters.petiole.petioles_per_internode = 1;
885 phytomer_parameters.petiole.pitch.uniformDistribution(-60, -40);
886 phytomer_parameters.petiole.radius = 0.0001;
887 phytomer_parameters.petiole.length = 0.0001;
888 phytomer_parameters.petiole.taper = 1;
889 phytomer_parameters.petiole.curvature = 0;
890 phytomer_parameters.petiole.color = phytomer_parameters.internode.color;
891 phytomer_parameters.petiole.length_segments = 1;
892
893 phytomer_parameters.leaf.leaves_per_petiole = 1;
894 phytomer_parameters.leaf.pitch = 0;
895 phytomer_parameters.leaf.yaw = 10;
896 phytomer_parameters.leaf.roll = 0;
897 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.12, 0.15);
898 phytomer_parameters.leaf.prototype = leaf_prototype;
899
900 phytomer_parameters.peduncle.length = 0.01;
901 phytomer_parameters.peduncle.radius = 0.001;
902 phytomer_parameters.peduncle.pitch.uniformDistribution(10, 30);
903 phytomer_parameters.peduncle.roll = 0;
904 phytomer_parameters.peduncle.curvature = -700;
905 phytomer_parameters.peduncle.color = phytomer_parameters.internode.color;
906 phytomer_parameters.peduncle.length_segments = 3;
907 phytomer_parameters.peduncle.radial_subdivisions = 6;
908
909 phytomer_parameters.inflorescence.flowers_per_peduncle = 1;
910 phytomer_parameters.inflorescence.pitch = 20;
911 phytomer_parameters.inflorescence.roll.uniformDistribution(-30, 30);
912 phytomer_parameters.inflorescence.flower_prototype_scale = 0.025;
913 phytomer_parameters.inflorescence.flower_prototype_function = AlmondFlowerPrototype;
914 phytomer_parameters.inflorescence.fruit_prototype_scale.uniformDistribution(0.12, 0.16);
915 phytomer_parameters.inflorescence.fruit_prototype_function = CapsicumFruitPrototype;
916 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction = 0.9;
917 phytomer_parameters.inflorescence.unique_prototypes = 10;
918
919 PhytomerParameters phytomer_parameters_secondary = phytomer_parameters;
920
921 // ---- Shoot Parameters ---- //
922
923 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
924 shoot_parameters.phytomer_parameters = phytomer_parameters;
925 shoot_parameters.phytomer_parameters.phytomer_creation_function = CapsicumPhytomerCreationFunction;
926
927 shoot_parameters.max_nodes = 30;
928 shoot_parameters.insertion_angle_tip = 35;
929 shoot_parameters.insertion_angle_decay_rate = 0;
930 shoot_parameters.internode_length_max = 0.04;
931 shoot_parameters.internode_length_min = 0.0;
932 shoot_parameters.internode_length_decay_rate = 0;
933 shoot_parameters.base_roll = 90;
934 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
935 shoot_parameters.gravitropic_curvature = 300;
936 shoot_parameters.tortuosity = 3;
937
938 shoot_parameters.phyllochron_min = 3;
939 shoot_parameters.elongation_rate_max = 0.1;
940 shoot_parameters.girth_area_factor = 2.f;
941 shoot_parameters.vegetative_bud_break_time = 30;
942 shoot_parameters.vegetative_bud_break_probability_min = 0.4;
943 shoot_parameters.vegetative_bud_break_probability_decay_rate = 0;
944 shoot_parameters.flower_bud_break_probability = 0.5;
945 shoot_parameters.fruit_set_probability = 0.05;
946 shoot_parameters.flowers_require_dormancy = false;
947 shoot_parameters.growth_requires_dormancy = false;
948 shoot_parameters.determinate_shoot_growth = true;
949
950 shoot_parameters.defineChildShootTypes({"secondary"}, {1.0});
951
952 defineShootType("mainstem", shoot_parameters);
953
954 ShootParameters shoot_parameters_secondary = shoot_parameters;
955 shoot_parameters_secondary.phytomer_parameters = phytomer_parameters_secondary;
956 shoot_parameters_secondary.max_nodes = 7;
957 shoot_parameters_secondary.phyllochron_min = 6;
958 shoot_parameters_secondary.vegetative_bud_break_probability_min = 0.2;
959
960 defineShootType("secondary", shoot_parameters_secondary);
961}
962
963uint PlantArchitecture::buildCapsicumPlant(const helios::vec3 &base_position) {
964
965 if (shoot_types.empty()) {
966 // automatically initialize capsicum plant shoots
967 initializeCapsicumShoots();
968 }
969
970 uint plantID = addPlantInstance(base_position, 0);
971
972 AxisRotation base_rotation = make_AxisRotation(0, context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
973 uint uID_stem = addBaseStemShoot(plantID, 1, base_rotation, 0.002, shoot_types.at("mainstem").internode_length_max.val(), 0.01, 0.01, 0, "mainstem");
974
975 breakPlantDormancy(plantID);
976
977 setPlantPhenologicalThresholds(plantID, 0, -1, -1, 75, 14, 1000, false);
978
979 plant_instances.at(plantID).max_age = 365;
980
981 return plantID;
982}
983
984void PlantArchitecture::initializeCheeseweedShoots() {
985
986 // ---- Leaf Prototype ---- //
987
988 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
989 leaf_prototype.OBJ_model_file = "plugins/plantarchitecture/assets/obj/CheeseweedLeaf.obj";
990
991 // ---- Phytomer Parameters ---- //
992
993 PhytomerParameters phytomer_parameters_cheeseweed(context_ptr->getRandomGenerator());
994
995 phytomer_parameters_cheeseweed.internode.pitch = 0;
996 phytomer_parameters_cheeseweed.internode.phyllotactic_angle.uniformDistribution(127.5f, 147.5);
997 phytomer_parameters_cheeseweed.internode.radius_initial = 0.0005;
998 phytomer_parameters_cheeseweed.internode.color = make_RGBcolor(0.60, 0.65, 0.40);
999 phytomer_parameters_cheeseweed.internode.length_segments = 1;
1000
1001 phytomer_parameters_cheeseweed.petiole.petioles_per_internode = 1;
1002 phytomer_parameters_cheeseweed.petiole.pitch.uniformDistribution(45, 75);
1003 phytomer_parameters_cheeseweed.petiole.radius = 0.0005;
1004 phytomer_parameters_cheeseweed.petiole.length.uniformDistribution(0.02, 0.06);
1005 phytomer_parameters_cheeseweed.petiole.taper = 0;
1006 phytomer_parameters_cheeseweed.petiole.curvature = -300;
1007 phytomer_parameters_cheeseweed.petiole.length_segments = 5;
1008 phytomer_parameters_cheeseweed.petiole.color = phytomer_parameters_cheeseweed.internode.color;
1009
1010 phytomer_parameters_cheeseweed.leaf.leaves_per_petiole = 1;
1011 phytomer_parameters_cheeseweed.leaf.pitch.uniformDistribution(-30, 0);
1012 phytomer_parameters_cheeseweed.leaf.yaw = 0;
1013 phytomer_parameters_cheeseweed.leaf.roll = 0;
1014 phytomer_parameters_cheeseweed.leaf.prototype_scale = 0.035;
1015 phytomer_parameters_cheeseweed.leaf.prototype = leaf_prototype;
1016
1017 // ---- Shoot Parameters ---- //
1018
1019 ShootParameters shoot_parameters_base(context_ptr->getRandomGenerator());
1020 shoot_parameters_base.phytomer_parameters = phytomer_parameters_cheeseweed;
1021 shoot_parameters_base.vegetative_bud_break_probability_min = 0.2;
1022 shoot_parameters_base.vegetative_bud_break_time = 6;
1023 shoot_parameters_base.phyllochron_min = 2;
1024 shoot_parameters_base.elongation_rate_max = 0.1;
1025 shoot_parameters_base.girth_area_factor = 10.f;
1026 shoot_parameters_base.gravitropic_curvature = 0;
1027 shoot_parameters_base.internode_length_max = 0.0015;
1028 shoot_parameters_base.internode_length_decay_rate = 0;
1029 shoot_parameters_base.flowers_require_dormancy = false;
1030 shoot_parameters_base.growth_requires_dormancy = false;
1031 shoot_parameters_base.flower_bud_break_probability = 0.;
1032 shoot_parameters_base.max_nodes = 8;
1033
1034 defineShootType("base", shoot_parameters_base);
1035}
1036
1037uint PlantArchitecture::buildCheeseweedPlant(const helios::vec3 &base_position) {
1038
1039 if (shoot_types.empty()) {
1040 // automatically initialize cheeseweed plant shoots
1041 initializeCheeseweedShoots();
1042 }
1043
1044 uint plantID = addPlantInstance(base_position, 0);
1045
1046 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(0, 0.f, 0.f), 0.0001, 0.0025, 0.1, 0.1, 0, "base");
1047
1048 breakPlantDormancy(plantID);
1049
1050 setPlantPhenologicalThresholds(plantID, 0, -1, -1, -1, -1, 1000, false);
1051
1052 plant_instances.at(plantID).max_age = 40;
1053
1054 return plantID;
1055}
1056
1057void PlantArchitecture::initializeCowpeaShoots() {
1058
1059 // ---- Leaf Prototype ---- //
1060
1061 LeafPrototype leaf_prototype_trifoliate(context_ptr->getRandomGenerator());
1062 leaf_prototype_trifoliate.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/CowpeaLeaf_tip_centered.png";
1063 leaf_prototype_trifoliate.leaf_texture_file[-1] = "plugins/plantarchitecture/assets/textures/CowpeaLeaf_left_centered.png";
1064 leaf_prototype_trifoliate.leaf_texture_file[1] = "plugins/plantarchitecture/assets/textures/CowpeaLeaf_right_centered.png";
1065 leaf_prototype_trifoliate.leaf_aspect_ratio = 0.7f;
1066 leaf_prototype_trifoliate.midrib_fold_fraction = 0.2;
1067 leaf_prototype_trifoliate.longitudinal_curvature.uniformDistribution(-0.3f, -0.1f);
1068 leaf_prototype_trifoliate.lateral_curvature = -0.4f;
1069 leaf_prototype_trifoliate.subdivisions = 6;
1070 leaf_prototype_trifoliate.unique_prototypes = 5;
1071 leaf_prototype_trifoliate.build_petiolule = true;
1072
1073 LeafPrototype leaf_prototype_unifoliate = leaf_prototype_trifoliate;
1074 leaf_prototype_unifoliate.leaf_texture_file.clear();
1075 leaf_prototype_unifoliate.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/CowpeaLeaf_unifoliate_centered.png";
1076
1077 // ---- Phytomer Parameters ---- //
1078
1079 PhytomerParameters phytomer_parameters_trifoliate(context_ptr->getRandomGenerator());
1080
1081 phytomer_parameters_trifoliate.internode.pitch = 20;
1082 phytomer_parameters_trifoliate.internode.phyllotactic_angle.uniformDistribution(145, 215);
1083 phytomer_parameters_trifoliate.internode.radius_initial = 0.0015;
1084 phytomer_parameters_trifoliate.internode.max_floral_buds_per_petiole = 1;
1085 phytomer_parameters_trifoliate.internode.max_vegetative_buds_per_petiole = 1;
1086 phytomer_parameters_trifoliate.internode.color = make_RGBcolor(0.15, 0.2, 0.1);
1087 phytomer_parameters_trifoliate.internode.length_segments = 2;
1088
1089 phytomer_parameters_trifoliate.petiole.petioles_per_internode = 1;
1090 phytomer_parameters_trifoliate.petiole.pitch.uniformDistribution(45, 60);
1091 phytomer_parameters_trifoliate.petiole.radius = 0.0018;
1092 phytomer_parameters_trifoliate.petiole.length.uniformDistribution(0.06, 0.08);
1093 phytomer_parameters_trifoliate.petiole.taper = 0.25;
1094 phytomer_parameters_trifoliate.petiole.curvature.uniformDistribution(-200, -50);
1095 phytomer_parameters_trifoliate.petiole.color = make_RGBcolor(0.2, 0.25, 0.06);
1096 phytomer_parameters_trifoliate.petiole.length_segments = 5;
1097 phytomer_parameters_trifoliate.petiole.radial_subdivisions = 6;
1098
1099 phytomer_parameters_trifoliate.leaf.leaves_per_petiole = 3;
1100 phytomer_parameters_trifoliate.leaf.pitch.normalDistribution(45, 20);
1101 phytomer_parameters_trifoliate.leaf.yaw = 10;
1102 phytomer_parameters_trifoliate.leaf.roll = -15;
1103 phytomer_parameters_trifoliate.leaf.leaflet_offset = 0.4;
1104 phytomer_parameters_trifoliate.leaf.leaflet_scale = 0.9;
1105 phytomer_parameters_trifoliate.leaf.prototype_scale.uniformDistribution(0.09, 0.12);
1106 phytomer_parameters_trifoliate.leaf.prototype = leaf_prototype_trifoliate;
1107
1108 phytomer_parameters_trifoliate.peduncle.length.uniformDistribution(0.3, 0.35);
1109 phytomer_parameters_trifoliate.peduncle.radius = 0.003;
1110 phytomer_parameters_trifoliate.peduncle.pitch.uniformDistribution(0, 30);
1111 phytomer_parameters_trifoliate.peduncle.roll = 90;
1112 phytomer_parameters_trifoliate.peduncle.curvature.uniformDistribution(50, 250);
1113 phytomer_parameters_trifoliate.peduncle.color = make_RGBcolor(0.17, 0.213, 0.051);
1114 phytomer_parameters_trifoliate.peduncle.length_segments = 6;
1115 phytomer_parameters_trifoliate.peduncle.radial_subdivisions = 6;
1116
1117 phytomer_parameters_trifoliate.inflorescence.flowers_per_peduncle.uniformDistribution(1, 3);
1118 phytomer_parameters_trifoliate.inflorescence.flower_offset = 0.025;
1119 phytomer_parameters_trifoliate.inflorescence.pitch.uniformDistribution(50, 70);
1120 phytomer_parameters_trifoliate.inflorescence.roll.uniformDistribution(-20, 20);
1121 phytomer_parameters_trifoliate.inflorescence.flower_prototype_scale = 0.03;
1122 phytomer_parameters_trifoliate.inflorescence.flower_prototype_function = CowpeaFlowerPrototype;
1123 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_scale.uniformDistribution(0.09, 0.1);
1124 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_function = CowpeaFruitPrototype;
1125 phytomer_parameters_trifoliate.inflorescence.fruit_gravity_factor_fraction.uniformDistribution(0.3, 0.5);
1126
1127 PhytomerParameters phytomer_parameters_unifoliate = phytomer_parameters_trifoliate;
1128 phytomer_parameters_unifoliate.internode.pitch = 0;
1129 phytomer_parameters_unifoliate.internode.max_vegetative_buds_per_petiole = 1;
1130 phytomer_parameters_unifoliate.internode.max_floral_buds_per_petiole = 0;
1131 phytomer_parameters_unifoliate.petiole.petioles_per_internode = 2;
1132 phytomer_parameters_unifoliate.petiole.length = 0.0001;
1133 phytomer_parameters_unifoliate.petiole.radius = 0.0004;
1134 phytomer_parameters_unifoliate.petiole.pitch.uniformDistribution(60, 80);
1135 phytomer_parameters_unifoliate.leaf.leaves_per_petiole = 1;
1136 phytomer_parameters_unifoliate.leaf.prototype_scale = 0.02;
1137 phytomer_parameters_unifoliate.leaf.pitch.uniformDistribution(-10, 10);
1138 phytomer_parameters_unifoliate.leaf.prototype = leaf_prototype_unifoliate;
1139
1140 // ---- Shoot Parameters ---- //
1141
1142 ShootParameters shoot_parameters_trifoliate(context_ptr->getRandomGenerator());
1143 shoot_parameters_trifoliate.phytomer_parameters = phytomer_parameters_trifoliate;
1144 shoot_parameters_trifoliate.phytomer_parameters.phytomer_creation_function = CowpeaPhytomerCreationFunction;
1145
1146 shoot_parameters_trifoliate.max_nodes = 20;
1147 shoot_parameters_trifoliate.insertion_angle_tip.uniformDistribution(40, 60);
1148 // shoot_parameters_trifoliate.child_insertion_angle_decay_rate = 0; (default)
1149 shoot_parameters_trifoliate.internode_length_max = 0.025;
1150 // shoot_parameters_trifoliate.child_internode_length_min = 0.0; (default)
1151 // shoot_parameters_trifoliate.child_internode_length_decay_rate = 0; (default)
1152 shoot_parameters_trifoliate.base_roll = 90;
1153 shoot_parameters_trifoliate.base_yaw.uniformDistribution(-20, 20);
1154 shoot_parameters_trifoliate.gravitropic_curvature = 200;
1155
1156 shoot_parameters_trifoliate.phyllochron_min = 2;
1157 shoot_parameters_trifoliate.elongation_rate_max = 0.1;
1158 shoot_parameters_trifoliate.girth_area_factor = 1.5f;
1159 shoot_parameters_trifoliate.vegetative_bud_break_time = 10;
1160 shoot_parameters_trifoliate.vegetative_bud_break_probability_min = 0.2;
1161 shoot_parameters_trifoliate.vegetative_bud_break_probability_decay_rate = -0.4;
1162 // shoot_parameters_trifoliate.max_terminal_floral_buds = 0; (default)
1163 shoot_parameters_trifoliate.flower_bud_break_probability.uniformDistribution(0.1, 0.15);
1164 shoot_parameters_trifoliate.fruit_set_probability = 0.4;
1165 // shoot_parameters_trifoliate.flowers_require_dormancy = false; (default)
1166 // shoot_parameters_trifoliate.growth_requires_dormancy = false; (default)
1167 // shoot_parameters_trifoliate.determinate_shoot_growth = true; (default)
1168
1169 shoot_parameters_trifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
1170
1171
1172 ShootParameters shoot_parameters_unifoliate = shoot_parameters_trifoliate;
1173 shoot_parameters_unifoliate.phytomer_parameters = phytomer_parameters_unifoliate;
1174 shoot_parameters_unifoliate.max_nodes = 1;
1175 shoot_parameters_unifoliate.girth_area_factor = 1.f;
1176 shoot_parameters_unifoliate.vegetative_bud_break_probability_min = 1;
1177 shoot_parameters_unifoliate.flower_bud_break_probability = 0;
1178 shoot_parameters_unifoliate.insertion_angle_tip = 40;
1179 shoot_parameters_unifoliate.insertion_angle_decay_rate = 0;
1180 shoot_parameters_unifoliate.vegetative_bud_break_time = 8;
1181 shoot_parameters_unifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
1182
1183 defineShootType("unifoliate", shoot_parameters_unifoliate);
1184 defineShootType("trifoliate", shoot_parameters_trifoliate);
1185}
1186
1187uint PlantArchitecture::buildCowpeaPlant(const helios::vec3 &base_position) {
1188
1189 if (shoot_types.empty()) {
1190 // automatically initialize cowpea plant shoots
1191 initializeCowpeaShoots();
1192 }
1193
1194 uint plantID = addPlantInstance(base_position, 0);
1195
1196 AxisRotation base_rotation = make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
1197 uint uID_unifoliate = addBaseStemShoot(plantID, 1, base_rotation, 0.0005, 0.03, 0.01, 0.01, 0, "unifoliate");
1198
1199 appendShoot(plantID, uID_unifoliate, 1, make_AxisRotation(0, 0, 0.5f * M_PI), shoot_types.at("trifoliate").phytomer_parameters.internode.radius_initial.val(), shoot_types.at("trifoliate").internode_length_max.val(), 0.1, 0.1, 0, "trifoliate");
1200
1201 breakPlantDormancy(plantID);
1202
1203 setPlantPhenologicalThresholds(plantID, 0, 40, 5, 5, 30, 1000, false);
1204
1205 plant_instances.at(plantID).max_age = 365;
1206
1207 return plantID;
1208}
1209
1210void PlantArchitecture::initializeGrapevineVSPShoots() {
1211
1212 // ---- Leaf Prototype ---- //
1213
1214 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1215 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/GrapeLeaf.png";
1216 leaf_prototype.leaf_aspect_ratio = 1.f;
1217 leaf_prototype.midrib_fold_fraction = 0.3f;
1218 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.4, 0.4);
1219 leaf_prototype.lateral_curvature = 0;
1220 leaf_prototype.wave_period = 0.3f;
1221 leaf_prototype.wave_amplitude = 0.1f;
1222 leaf_prototype.subdivisions = 5;
1223 leaf_prototype.unique_prototypes = 10;
1224 leaf_prototype.leaf_offset = make_vec3(-0.3, 0, 0);
1225
1226 // ---- Phytomer Parameters ---- //
1227
1228 PhytomerParameters phytomer_parameters_grapevine(context_ptr->getRandomGenerator());
1229
1230 phytomer_parameters_grapevine.internode.pitch = 20;
1231 phytomer_parameters_grapevine.internode.phyllotactic_angle.uniformDistribution(160, 200);
1232 phytomer_parameters_grapevine.internode.radius_initial = 0.003;
1233 phytomer_parameters_grapevine.internode.color = make_RGBcolor(0.23, 0.13, 0.062);
1234 phytomer_parameters_grapevine.internode.length_segments = 1;
1235 phytomer_parameters_grapevine.internode.max_floral_buds_per_petiole = 1;
1236 phytomer_parameters_grapevine.internode.max_vegetative_buds_per_petiole = 1;
1237
1238 phytomer_parameters_grapevine.petiole.petioles_per_internode = 1;
1239 phytomer_parameters_grapevine.petiole.color = make_RGBcolor(0.13, 0.066, 0.03);
1240 phytomer_parameters_grapevine.petiole.pitch.uniformDistribution(45, 70);
1241 phytomer_parameters_grapevine.petiole.radius = 0.0025;
1242 phytomer_parameters_grapevine.petiole.length = 0.1;
1243 phytomer_parameters_grapevine.petiole.taper = 0;
1244 phytomer_parameters_grapevine.petiole.curvature = 0;
1245 phytomer_parameters_grapevine.petiole.length_segments = 1;
1246
1247 phytomer_parameters_grapevine.leaf.leaves_per_petiole = 1;
1248 phytomer_parameters_grapevine.leaf.pitch.uniformDistribution(-110, -80);
1249 phytomer_parameters_grapevine.leaf.yaw.uniformDistribution(-20, 20);
1250 phytomer_parameters_grapevine.leaf.roll.uniformDistribution(-5, 5);
1251 phytomer_parameters_grapevine.leaf.prototype_scale = 0.2;
1252 phytomer_parameters_grapevine.leaf.prototype = leaf_prototype;
1253
1254 phytomer_parameters_grapevine.peduncle.length = 0.08;
1255 phytomer_parameters_grapevine.peduncle.pitch.uniformDistribution(50, 90);
1256 phytomer_parameters_grapevine.peduncle.color = make_RGBcolor(0.32, 0.05, 0.13);
1257
1258 phytomer_parameters_grapevine.inflorescence.flowers_per_peduncle = 1;
1259 phytomer_parameters_grapevine.inflorescence.pitch = 0;
1260 // phytomer_parameters_grapevine.inflorescence.flower_prototype_function = GrapevineFlowerPrototype;
1261 phytomer_parameters_grapevine.inflorescence.flower_prototype_scale = 0.04;
1262 phytomer_parameters_grapevine.inflorescence.fruit_prototype_function = GrapevineFruitPrototype;
1263 phytomer_parameters_grapevine.inflorescence.fruit_prototype_scale = 0.04;
1264 phytomer_parameters_grapevine.inflorescence.fruit_gravity_factor_fraction = 0.7;
1265
1266 phytomer_parameters_grapevine.phytomer_creation_function = GrapevinePhytomerCreationFunction;
1267 // phytomer_parameters_grapevine.phytomer_callback_function = GrapevinePhytomerCallbackFunction;
1268
1269 // ---- Shoot Parameters ---- //
1270
1271 ShootParameters shoot_parameters_main(context_ptr->getRandomGenerator());
1272 shoot_parameters_main.phytomer_parameters = phytomer_parameters_grapevine;
1273 shoot_parameters_main.vegetative_bud_break_probability_min = 0.075;
1274 shoot_parameters_main.vegetative_bud_break_probability_decay_rate = 1.;
1275 shoot_parameters_main.vegetative_bud_break_time = 30;
1276 shoot_parameters_main.phyllochron_min.uniformDistribution(1.75, 2.25);
1277 shoot_parameters_main.elongation_rate_max = 0.15;
1278 shoot_parameters_main.girth_area_factor = 1.f;
1279 shoot_parameters_main.gravitropic_curvature = 400;
1280 shoot_parameters_main.tortuosity = 15;
1281 shoot_parameters_main.internode_length_max.uniformDistribution(0.06, 0.08);
1282 shoot_parameters_main.internode_length_decay_rate = 0;
1283 shoot_parameters_main.insertion_angle_tip = 45;
1284 shoot_parameters_main.insertion_angle_decay_rate = 0;
1285 shoot_parameters_main.flowers_require_dormancy = false;
1286 shoot_parameters_main.growth_requires_dormancy = false;
1287 shoot_parameters_main.determinate_shoot_growth = false;
1288 shoot_parameters_main.max_terminal_floral_buds = 0;
1289 shoot_parameters_main.flower_bud_break_probability = 0.5;
1290 shoot_parameters_main.fruit_set_probability = 0.2;
1291 shoot_parameters_main.max_nodes = 20;
1292 shoot_parameters_main.base_roll.uniformDistribution(90 - 25, 90 + 25);
1293 shoot_parameters_main.base_yaw = 0;
1294
1295 ShootParameters shoot_parameters_cane = shoot_parameters_main;
1296 // shoot_parameters_cane.phytomer_parameters.internode.image_texture = "plugins/plantarchitecture/assets/textures/GrapeBark.jpg";
1297 shoot_parameters_cane.phytomer_parameters.internode.pitch = 0;
1298 shoot_parameters_cane.phytomer_parameters.internode.radial_subdivisions = 15;
1299 shoot_parameters_cane.phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
1300 shoot_parameters_cane.phytomer_parameters.internode.phyllotactic_angle = 0;
1301 shoot_parameters_cane.insertion_angle_tip.uniformDistribution(60, 120);
1302 shoot_parameters_cane.girth_area_factor = 0.7f;
1303 shoot_parameters_cane.max_nodes = 9;
1304 shoot_parameters_cane.gravitropic_curvature.uniformDistribution(-20, 20);
1305 shoot_parameters_cane.tortuosity = 1;
1306 shoot_parameters_cane.gravitropic_curvature = 10;
1307 shoot_parameters_cane.vegetative_bud_break_probability_min = 0.9;
1308 shoot_parameters_cane.defineChildShootTypes({"grapevine_shoot"}, {1.f});
1309
1310 ShootParameters shoot_parameters_trunk = shoot_parameters_main;
1311 shoot_parameters_trunk.phytomer_parameters.internode.image_texture = "plugins/plantarchitecture/assets/textures/GrapeBark.jpg";
1312 shoot_parameters_trunk.phytomer_parameters.internode.pitch = 0;
1313 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
1314 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.05;
1315 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 25;
1316 shoot_parameters_trunk.phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
1317 shoot_parameters_trunk.phyllochron_min = 2.5;
1318 shoot_parameters_trunk.insertion_angle_tip = 90;
1319 shoot_parameters_trunk.girth_area_factor = 0;
1320 shoot_parameters_trunk.max_nodes = 18;
1321 shoot_parameters_trunk.tortuosity = 0;
1322 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
1323 shoot_parameters_trunk.defineChildShootTypes({"grapevine_shoot"}, {1.f});
1324
1325 defineShootType("grapevine_trunk", shoot_parameters_trunk);
1326 defineShootType("grapevine_cane", shoot_parameters_cane);
1327 defineShootType("grapevine_shoot", shoot_parameters_main);
1328}
1329
1330uint PlantArchitecture::buildGrapevineVSP(const helios::vec3 &base_position) {
1331
1332 if (shoot_types.empty()) {
1333 // automatically initialize grapevine plant shoots
1334 initializeGrapevineVSPShoots();
1335 }
1336
1337 uint plantID = addPlantInstance(base_position, 0);
1338
1339 uint uID_stem = addBaseStemShoot(plantID, 8, make_AxisRotation(context_ptr->randu(0, 0.05 * M_PI), 0, 0), shoot_types.at("grapevine_trunk").phytomer_parameters.internode.radius_initial.val(), 0.1, 1, 1, 0.1, "grapevine_trunk");
1340
1341 uint uID_cane_L = appendShoot(plantID, uID_stem, 8, make_AxisRotation(context_ptr->randu(float(0.45f * M_PI), 0.52f * M_PI), 0, M_PI), 0.005, 0.15, 1, 1, 0.5, "grapevine_cane");
1342 uint uID_cane_R = appendShoot(plantID, uID_stem, 8, make_AxisRotation(context_ptr->randu(float(0.45f * M_PI), 0.52f * M_PI), M_PI, M_PI), 0.005, 0.15, 1, 1, 0.5, "grapevine_cane");
1343
1344 // makePlantDormant(plantID);
1345
1346 removeShootLeaves(plantID, uID_stem);
1347 removeShootLeaves(plantID, uID_cane_L);
1348 removeShootLeaves(plantID, uID_cane_R);
1349
1350 setPlantPhenologicalThresholds(plantID, 165, -1, -1, 45, 45, 200, false);
1351
1352 plant_instances.at(plantID).max_age = 365;
1353
1354 return plantID;
1355}
1356
1357void PlantArchitecture::initializeGrapevineWyeShoots() {
1358
1359 // ---- Leaf Prototype ---- //
1360
1361 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1362 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/GrapeLeaf.png";
1363 leaf_prototype.leaf_aspect_ratio = 1.f;
1364 leaf_prototype.midrib_fold_fraction = 0.3f;
1365 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.4, 0.4);
1366 leaf_prototype.lateral_curvature = 0;
1367 leaf_prototype.wave_period = 0.3f;
1368 leaf_prototype.wave_amplitude = 0.1f;
1369 leaf_prototype.subdivisions = 5;
1370 leaf_prototype.unique_prototypes = 10;
1371 leaf_prototype.leaf_offset = make_vec3(-0.3, 0, 0);
1372
1373 // ---- Phytomer Parameters ---- //
1374
1375 PhytomerParameters phytomer_parameters_grapevine(context_ptr->getRandomGenerator());
1376
1377 phytomer_parameters_grapevine.internode.pitch = 20;
1378 phytomer_parameters_grapevine.internode.phyllotactic_angle.uniformDistribution(160, 200);
1379 phytomer_parameters_grapevine.internode.radius_initial = 0.003;
1380 phytomer_parameters_grapevine.internode.color = make_RGBcolor(0.23, 0.13, 0.062);
1381 phytomer_parameters_grapevine.internode.length_segments = 1;
1382 phytomer_parameters_grapevine.internode.max_floral_buds_per_petiole = 1;
1383 phytomer_parameters_grapevine.internode.max_vegetative_buds_per_petiole = 1;
1384
1385 phytomer_parameters_grapevine.petiole.petioles_per_internode = 1;
1386 phytomer_parameters_grapevine.petiole.color = make_RGBcolor(0.13, 0.125, 0.03);
1387 phytomer_parameters_grapevine.petiole.pitch.uniformDistribution(45, 70);
1388 phytomer_parameters_grapevine.petiole.radius = 0.0025;
1389 phytomer_parameters_grapevine.petiole.length = 0.1;
1390 phytomer_parameters_grapevine.petiole.taper = 0;
1391 phytomer_parameters_grapevine.petiole.curvature = 0;
1392 phytomer_parameters_grapevine.petiole.length_segments = 1;
1393
1394 phytomer_parameters_grapevine.leaf.leaves_per_petiole = 1;
1395 phytomer_parameters_grapevine.leaf.pitch.uniformDistribution(-110, -80);
1396 phytomer_parameters_grapevine.leaf.yaw.uniformDistribution(-20, 20);
1397 phytomer_parameters_grapevine.leaf.roll.uniformDistribution(-5, 5);
1398 phytomer_parameters_grapevine.leaf.prototype_scale = 0.2;
1399 phytomer_parameters_grapevine.leaf.prototype = leaf_prototype;
1400
1401 phytomer_parameters_grapevine.peduncle.length = 0.04;
1402 phytomer_parameters_grapevine.peduncle.radius = 0.005;
1403 phytomer_parameters_grapevine.peduncle.color = make_RGBcolor(0.13, 0.125, 0.03);
1404 phytomer_parameters_grapevine.peduncle.pitch.uniformDistribution(80, 100);
1405
1406 phytomer_parameters_grapevine.inflorescence.flowers_per_peduncle = 1;
1407 phytomer_parameters_grapevine.inflorescence.pitch = 0;
1408 // phytomer_parameters_grapevine.inflorescence.flower_prototype_function = GrapevineFlowerPrototype;
1409 phytomer_parameters_grapevine.inflorescence.flower_prototype_scale = 0.04;
1410 phytomer_parameters_grapevine.inflorescence.fruit_prototype_function = GrapevineFruitPrototype;
1411 phytomer_parameters_grapevine.inflorescence.fruit_prototype_scale = 0.04;
1412 phytomer_parameters_grapevine.inflorescence.fruit_gravity_factor_fraction = 0.9;
1413
1414 phytomer_parameters_grapevine.phytomer_creation_function = GrapevinePhytomerCreationFunction;
1415 // phytomer_parameters_grapevine.phytomer_callback_function = GrapevinePhytomerCallbackFunction;
1416
1417 // ---- Shoot Parameters ---- //
1418
1419 ShootParameters shoot_parameters_main(context_ptr->getRandomGenerator());
1420 shoot_parameters_main.phytomer_parameters = phytomer_parameters_grapevine;
1421 shoot_parameters_main.vegetative_bud_break_probability_min = 0.025;
1422 shoot_parameters_main.vegetative_bud_break_probability_decay_rate = -1.;
1423 shoot_parameters_main.vegetative_bud_break_time = 30;
1424 shoot_parameters_main.phyllochron_min.uniformDistribution(2.5, 3.5);
1425 shoot_parameters_main.elongation_rate_max = 0.15;
1426 shoot_parameters_main.girth_area_factor = 0.8f;
1427 shoot_parameters_main.gravitropic_curvature.uniformDistribution(0, 100);
1428 shoot_parameters_main.tortuosity = 10;
1429 shoot_parameters_main.internode_length_max.uniformDistribution(0.06, 0.08);
1430 shoot_parameters_main.internode_length_decay_rate = 0;
1431 shoot_parameters_main.insertion_angle_tip = 45;
1432 shoot_parameters_main.insertion_angle_decay_rate = 0;
1433 shoot_parameters_main.flowers_require_dormancy = false;
1434 shoot_parameters_main.growth_requires_dormancy = false;
1435 shoot_parameters_main.determinate_shoot_growth = false;
1436 shoot_parameters_main.max_terminal_floral_buds = 0;
1437 shoot_parameters_main.flower_bud_break_probability = 0.5;
1438 shoot_parameters_main.fruit_set_probability = 0.2;
1439 shoot_parameters_main.max_nodes.uniformDistribution(14, 18);
1440 shoot_parameters_main.base_roll.uniformDistribution(90 - 25, 90 + 25);
1441 shoot_parameters_main.base_yaw.uniformDistribution(-50, 50);
1442
1443 ShootParameters shoot_parameters_cordon = shoot_parameters_main;
1444 shoot_parameters_cordon.phytomer_parameters.internode.image_texture = "plugins/plantarchitecture/assets/textures/GrapeBark.jpg";
1445 shoot_parameters_cordon.phytomer_parameters.internode.pitch = 0;
1446 shoot_parameters_cordon.phytomer_parameters.internode.radial_subdivisions = 15;
1447 shoot_parameters_cordon.phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
1448 shoot_parameters_cordon.phytomer_parameters.internode.phyllotactic_angle = 0;
1449 shoot_parameters_cordon.insertion_angle_tip.uniformDistribution(60, 120);
1450 shoot_parameters_cordon.girth_area_factor = 3.5f;
1451 shoot_parameters_cordon.max_nodes = 8;
1452 shoot_parameters_cordon.tortuosity = 1;
1453 shoot_parameters_cordon.gravitropic_curvature = 0;
1454 shoot_parameters_cordon.vegetative_bud_break_probability_min = 0.9;
1455 shoot_parameters_cordon.base_yaw = 0;
1456 shoot_parameters_cordon.defineChildShootTypes({"grapevine_shoot"}, {1.f});
1457
1458 ShootParameters shoot_parameters_trunk = shoot_parameters_main;
1459 shoot_parameters_trunk.phytomer_parameters.internode.image_texture = "plugins/plantarchitecture/assets/textures/GrapeBark.jpg";
1460 shoot_parameters_trunk.phytomer_parameters.internode.pitch = 0;
1461 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
1462 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.05;
1463 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 25;
1464 shoot_parameters_trunk.phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
1465 shoot_parameters_trunk.phyllochron_min = 2.5;
1466 shoot_parameters_trunk.insertion_angle_tip = 90;
1467 shoot_parameters_trunk.girth_area_factor = 0;
1468 shoot_parameters_trunk.max_nodes = 18;
1469 shoot_parameters_trunk.tortuosity = 2;
1470 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
1471 shoot_parameters_trunk.defineChildShootTypes({"grapevine_shoot"}, {1.f});
1472
1473 defineShootType("grapevine_trunk", shoot_parameters_trunk);
1474 defineShootType("grapevine_cordon", shoot_parameters_cordon);
1475 defineShootType("grapevine_shoot", shoot_parameters_main);
1476}
1477
1478uint PlantArchitecture::buildGrapevineWye(const helios::vec3 &base_position) {
1479
1480 if (shoot_types.empty()) {
1481 // automatically initialize grapevine plant shoots
1482 initializeGrapevineWyeShoots();
1483 }
1484
1485 std::vector<std::vector<vec3>> trellis_points;
1486
1487 float wire_spacing = 0.6f;
1488 float head_height = 1.6;
1489 float vine_spacing = 1.8;
1490
1491 // fruiting wires
1492 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, -0.5f * wire_spacing, head_height), make_vec3(0.5f * vine_spacing, -0.5f * wire_spacing, head_height), 8));
1493 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, 0.5f * wire_spacing, head_height), make_vec3(0.5f * vine_spacing, 0.5f * wire_spacing, head_height), 8));
1494
1495 // first catch wires (these don't exist in a real Wye trellis, but are needed to keep the vines from falling through the wires)
1496 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, -0.5f * wire_spacing - 0.15f, head_height + 0.15f), make_vec3(0.5f * vine_spacing, -0.5f * wire_spacing - 0.15f, head_height + 0.15f), 8));
1497 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, 0.5f * wire_spacing + 0.15f, head_height + 0.15f), make_vec3(0.5f * vine_spacing, 0.5f * wire_spacing + 0.15f, head_height + 0.15f), 8));
1498
1499 // second catch wires
1500 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, -0.5f * wire_spacing - 0.35f, head_height + 0.35f), make_vec3(0.5f * vine_spacing, -0.5f * wire_spacing - 0.35f, head_height + 0.35f), 8));
1501 trellis_points.push_back(linspace(make_vec3(-0.5f * vine_spacing, 0.5f * wire_spacing + 0.35f, head_height + 0.35f), make_vec3(0.5f * vine_spacing, 0.5f * wire_spacing + 0.35f, head_height + 0.35f), 8));
1502
1503 for (int j = 0; j < trellis_points.size(); j++) {
1504 for (int i = 0; i < trellis_points[j].size(); i++) {
1505 trellis_points.at(j).at(i) += base_position;
1506 }
1507 }
1508
1509 uint plantID = addPlantInstance(base_position, 0);
1510
1511 // Set plant-specific attraction points for this grapevine's trellis system
1512 setPlantAttractionPoints(plantID, flatten(trellis_points), 45.f, 0.5f, 0.5);
1513
1514 uint uID_stem = addBaseStemShoot(plantID, 8, make_AxisRotation(0., 0, 0), shoot_types.at("grapevine_trunk").phytomer_parameters.internode.radius_initial.val(), 0.165, 1, 1, 0.1, "grapevine_trunk");
1515
1516 uint uID_upright_L = appendShoot(plantID, uID_stem, 3, make_AxisRotation(deg2rad(context_ptr->randu(42.f, 48.f)), 0, M_PI), 0.03, 0.14, 1, 1, 0.2, "grapevine_trunk");
1517 uint uID_upright_R = appendShoot(plantID, uID_stem, 3, make_AxisRotation(deg2rad(context_ptr->randu(42.f, 48.f)), M_PI, M_PI), 0.03, 0.14, 1, 1, 0.2, "grapevine_trunk");
1518
1519 uint uID_cordon_L1 = appendShoot(plantID, uID_upright_L, 8, make_AxisRotation(deg2rad(-90), 0.5 * M_PI, -0.2), 0.02, 0.11, 1, 1, 0.5, "grapevine_cordon");
1520 uint uID_cordon_L2 = appendShoot(plantID, uID_upright_L, 8, make_AxisRotation(deg2rad(-90), -0.5 * M_PI, 0.2), 0.02, 0.11, 1, 1, 0.5, "grapevine_cordon");
1521
1522 uint uID_cordon_R1 = appendShoot(plantID, uID_upright_R, 8, make_AxisRotation(deg2rad(-90), 0.5 * M_PI, 0.2), 0.02, 0.11, 1, 1, 0.5, "grapevine_cordon");
1523 uint uID_cordon_R2 = appendShoot(plantID, uID_upright_R, 8, make_AxisRotation(deg2rad(-90), -0.5 * M_PI, -0.2), 0.02, 0.11, 1, 1, 0.5, "grapevine_cordon");
1524
1525 removeShootLeaves(plantID, uID_stem);
1526 removeShootLeaves(plantID, uID_upright_L);
1527 removeShootLeaves(plantID, uID_upright_R);
1528 removeShootLeaves(plantID, uID_cordon_L1);
1529 removeShootLeaves(plantID, uID_cordon_L2);
1530 removeShootLeaves(plantID, uID_cordon_R1);
1531 removeShootLeaves(plantID, uID_cordon_R2);
1532
1533 removeShootVegetativeBuds(plantID, uID_upright_L);
1534 removeShootVegetativeBuds(plantID, uID_upright_R);
1535
1536 setPlantPhenologicalThresholds(plantID, 165, -1, -1, 45, 45, 200, false);
1537
1538 plant_instances.at(plantID).max_age = 365;
1539
1540 return plantID;
1541}
1542
1543void PlantArchitecture::initializeGroundCherryWeedShoots() {
1544
1545 // ---- Leaf Prototype ---- //
1546
1547 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1548 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/GroundCherryLeaf.png";
1549 leaf_prototype.leaf_aspect_ratio.uniformDistribution(0.3, 0.5);
1550 leaf_prototype.midrib_fold_fraction = 0.2f;
1551 leaf_prototype.longitudinal_curvature = 0.1f;
1552 ;
1553 leaf_prototype.lateral_curvature = -0.3f;
1554 leaf_prototype.wave_period = 0.35f;
1555 leaf_prototype.wave_amplitude = 0.08f;
1556 leaf_prototype.subdivisions = 6;
1557 leaf_prototype.unique_prototypes = 5;
1558
1559 // ---- Phytomer Parameters ---- //
1560
1561 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
1562
1563 phytomer_parameters.internode.pitch = 5;
1564 phytomer_parameters.internode.phyllotactic_angle = 137.5;
1565 phytomer_parameters.internode.radius_initial = 0.0005;
1566 phytomer_parameters.internode.color = make_RGBcolor(0.213, 0.270, 0.056);
1567 phytomer_parameters.internode.length_segments = 1;
1568
1569 phytomer_parameters.petiole.petioles_per_internode = 1;
1570 phytomer_parameters.petiole.pitch.uniformDistribution(45, 60);
1571 phytomer_parameters.petiole.radius = 0.0005;
1572 phytomer_parameters.petiole.length = 0.025;
1573 phytomer_parameters.petiole.taper = 0.15;
1574 phytomer_parameters.petiole.curvature.uniformDistribution(-150, -50);
1575 phytomer_parameters.petiole.color = phytomer_parameters.internode.color;
1576 phytomer_parameters.petiole.length_segments = 2;
1577
1578 phytomer_parameters.leaf.leaves_per_petiole = 1;
1579 phytomer_parameters.leaf.pitch.uniformDistribution(-30, 5);
1580 phytomer_parameters.leaf.yaw = 10;
1581 phytomer_parameters.leaf.roll = 0;
1582 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.06, 0.08);
1583 phytomer_parameters.leaf.prototype = leaf_prototype;
1584
1585 phytomer_parameters.peduncle.length = 0.01;
1586 phytomer_parameters.peduncle.radius = 0.001;
1587 phytomer_parameters.peduncle.pitch = 20;
1588 phytomer_parameters.peduncle.roll = 0;
1589 phytomer_parameters.peduncle.curvature = -700;
1590 phytomer_parameters.peduncle.color = phytomer_parameters.internode.color;
1591 phytomer_parameters.peduncle.length_segments = 2;
1592 phytomer_parameters.peduncle.radial_subdivisions = 6;
1593
1594 phytomer_parameters.inflorescence.flowers_per_peduncle = 1;
1595 phytomer_parameters.inflorescence.pitch = 0;
1596 phytomer_parameters.inflorescence.roll.uniformDistribution(-30, 30);
1597 phytomer_parameters.inflorescence.flower_prototype_scale = 0.01;
1598 phytomer_parameters.inflorescence.flower_prototype_function = BindweedFlowerPrototype;
1599 phytomer_parameters.inflorescence.fruit_prototype_scale = 0.06;
1600 // phytomer_parameters.inflorescence.fruit_prototype_function = GroundCherryFruitPrototype;
1601 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction = 0.75;
1602
1603 // ---- Shoot Parameters ---- //
1604
1605 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
1606 shoot_parameters.phytomer_parameters = phytomer_parameters;
1607 // shoot_parameters.phytomer_parameters.phytomer_creation_function = TomatoPhytomerCreationFunction;
1608
1609 shoot_parameters.max_nodes = 26;
1610 shoot_parameters.insertion_angle_tip = 50;
1611 shoot_parameters.insertion_angle_decay_rate = 0;
1612 shoot_parameters.internode_length_max = 0.015;
1613 shoot_parameters.internode_length_min = 0.0;
1614 shoot_parameters.internode_length_decay_rate = 0;
1615 shoot_parameters.base_roll = 90;
1616 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
1617 shoot_parameters.gravitropic_curvature = 700;
1618 shoot_parameters.tortuosity = 3;
1619
1620 shoot_parameters.phyllochron_min = 1;
1621 shoot_parameters.elongation_rate_max = 0.1;
1622 shoot_parameters.girth_area_factor = 2.f;
1623 shoot_parameters.vegetative_bud_break_time = 10;
1624 shoot_parameters.vegetative_bud_break_probability_min = 0.1;
1625 shoot_parameters.vegetative_bud_break_probability_decay_rate = -0.5;
1626 shoot_parameters.flower_bud_break_probability = 0.25;
1627 shoot_parameters.fruit_set_probability = 0.5;
1628 shoot_parameters.flowers_require_dormancy = false;
1629 shoot_parameters.growth_requires_dormancy = false;
1630 shoot_parameters.determinate_shoot_growth = false;
1631
1632 shoot_parameters.defineChildShootTypes({"mainstem"}, {1.0});
1633
1634 defineShootType("mainstem", shoot_parameters);
1635}
1636
1637uint PlantArchitecture::buildGroundCherryWeedPlant(const helios::vec3 &base_position) {
1638
1639 if (shoot_types.empty()) {
1640 // automatically initialize ground cherry plant shoots
1641 initializeGroundCherryWeedShoots();
1642 }
1643
1644 uint plantID = addPlantInstance(base_position, 0);
1645
1646 AxisRotation base_rotation = make_AxisRotation(0, context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
1647 uint uID_stem = addBaseStemShoot(plantID, 1, base_rotation, 0.0025, 0.018, 0.01, 0.01, 0, "mainstem");
1648
1649 breakPlantDormancy(plantID);
1650
1651 setPlantPhenologicalThresholds(plantID, 0, 20, -1, 20, 30, 1000, false);
1652
1653 plant_instances.at(plantID).max_age = 80;
1654
1655 return plantID;
1656}
1657
1658void PlantArchitecture::initializeMaizeShoots() {
1659
1660 // ---- Leaf Prototype ---- //
1661
1662 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1663 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SorghumLeaf.png";
1664 leaf_prototype.leaf_aspect_ratio = 0.25f;
1665 leaf_prototype.midrib_fold_fraction = 0.3f;
1666 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.45, -0.3);
1667 leaf_prototype.lateral_curvature = -0.3f;
1668 ;
1669 leaf_prototype.petiole_roll = 0.04f;
1670 leaf_prototype.wave_period = 0.1f;
1671 leaf_prototype.wave_amplitude = 0.1f;
1672 leaf_prototype.leaf_buckle_length.uniformDistribution(0.4, 0.6);
1673 leaf_prototype.leaf_buckle_angle.uniformDistribution(40, 50);
1674 leaf_prototype.subdivisions = 50;
1675 leaf_prototype.unique_prototypes = 10;
1676
1677 // ---- Phytomer Parameters ---- //
1678
1679 PhytomerParameters phytomer_parameters_maize(context_ptr->getRandomGenerator());
1680
1681 phytomer_parameters_maize.internode.pitch = 0;
1682 phytomer_parameters_maize.internode.phyllotactic_angle.uniformDistribution(170, 190);
1683 phytomer_parameters_maize.internode.radius_initial = 0.0075;
1684 phytomer_parameters_maize.internode.color = make_RGBcolor(0.126, 0.182, 0.084);
1685 phytomer_parameters_maize.internode.length_segments = 2;
1686 phytomer_parameters_maize.internode.radial_subdivisions = 10;
1687 phytomer_parameters_maize.internode.max_floral_buds_per_petiole = 1;
1688 phytomer_parameters_maize.internode.max_vegetative_buds_per_petiole = 0;
1689
1690 phytomer_parameters_maize.petiole.petioles_per_internode = 1;
1691 phytomer_parameters_maize.petiole.pitch.uniformDistribution(-40, -20);
1692 phytomer_parameters_maize.petiole.radius = 0.0;
1693 phytomer_parameters_maize.petiole.length = 0.05;
1694 phytomer_parameters_maize.petiole.taper = 0;
1695 phytomer_parameters_maize.petiole.curvature = 0;
1696 phytomer_parameters_maize.petiole.length_segments = 1;
1697
1698 phytomer_parameters_maize.leaf.leaves_per_petiole = 1;
1699 phytomer_parameters_maize.leaf.pitch = 0;
1700 phytomer_parameters_maize.leaf.yaw = 0;
1701 phytomer_parameters_maize.leaf.roll = 0;
1702 phytomer_parameters_maize.leaf.prototype_scale = 0.6;
1703 phytomer_parameters_maize.leaf.prototype = leaf_prototype;
1704
1705 phytomer_parameters_maize.peduncle.length = 0.14f;
1706 phytomer_parameters_maize.peduncle.radius = 0.004;
1707 phytomer_parameters_maize.peduncle.curvature = 0;
1708 phytomer_parameters_maize.peduncle.color = phytomer_parameters_maize.internode.color;
1709 phytomer_parameters_maize.peduncle.radial_subdivisions = 6;
1710 phytomer_parameters_maize.peduncle.length_segments = 2;
1711
1712 phytomer_parameters_maize.inflorescence.flowers_per_peduncle = 7;
1713 phytomer_parameters_maize.inflorescence.pitch.uniformDistribution(0, 30);
1714 phytomer_parameters_maize.inflorescence.roll = 0;
1715 phytomer_parameters_maize.inflorescence.flower_offset = 0.1;
1716 phytomer_parameters_maize.inflorescence.fruit_prototype_scale = 0.15;
1717 phytomer_parameters_maize.inflorescence.fruit_prototype_function = MaizeTasselPrototype;
1718
1719 phytomer_parameters_maize.phytomer_creation_function = MaizePhytomerCreationFunction;
1720
1721 // ---- Shoot Parameters ---- //
1722
1723 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
1724 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters_maize;
1725 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0.5;
1726 shoot_parameters_mainstem.flower_bud_break_probability = 1;
1727 shoot_parameters_mainstem.phyllochron_min = 2;
1728 shoot_parameters_mainstem.elongation_rate_max = 0.1;
1729 shoot_parameters_mainstem.girth_area_factor = 6.f;
1730 shoot_parameters_mainstem.gravitropic_curvature.uniformDistribution(-500, 0);
1731 shoot_parameters_mainstem.internode_length_max = 0.22;
1732 shoot_parameters_mainstem.tortuosity = 1.f;
1733 shoot_parameters_mainstem.internode_length_decay_rate = 0;
1734 shoot_parameters_mainstem.flowers_require_dormancy = false;
1735 shoot_parameters_mainstem.growth_requires_dormancy = false;
1736 shoot_parameters_mainstem.determinate_shoot_growth = false;
1737 shoot_parameters_mainstem.flower_bud_break_probability = 1.0;
1738 shoot_parameters_mainstem.fruit_set_probability = 1.0;
1739 shoot_parameters_mainstem.defineChildShootTypes({"mainstem"}, {1.0});
1740 shoot_parameters_mainstem.max_nodes = 17;
1741 shoot_parameters_mainstem.max_terminal_floral_buds = 1;
1742
1743 defineShootType("mainstem", shoot_parameters_mainstem);
1744}
1745
1746uint PlantArchitecture::buildMaizePlant(const helios::vec3 &base_position) {
1747
1748 if (shoot_types.empty()) {
1749 // automatically initialize maize plant shoots
1750 initializeMaizeShoots();
1751 }
1752
1753 uint plantID = addPlantInstance(base_position, 0);
1754
1755 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(context_ptr->randu(0.f, 0.035f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)), 0.003, 0.08, 0.01, 0.01, 0.2, "mainstem");
1756
1757 breakPlantDormancy(plantID);
1758
1759 setPlantPhenologicalThresholds(plantID, 0, -1, -1, 4, 10, 1000, false);
1760
1761 plant_instances.at(plantID).max_age = 365;
1762
1763 return plantID;
1764}
1765
1766void PlantArchitecture::initializeOliveTreeShoots() {
1767
1768 // ---- Leaf Prototype ---- //
1769
1770 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1771 leaf_prototype.prototype_function = OliveLeafPrototype;
1772 leaf_prototype.unique_prototypes = 1;
1773
1774 // ---- Phytomer Parameters ---- //
1775
1776 PhytomerParameters phytomer_parameters_olive(context_ptr->getRandomGenerator());
1777
1778 phytomer_parameters_olive.internode.pitch = 0;
1779 phytomer_parameters_olive.internode.phyllotactic_angle.uniformDistribution(80, 100);
1780 phytomer_parameters_olive.internode.radius_initial = 0.002;
1781 phytomer_parameters_olive.internode.length_segments = 1;
1782 phytomer_parameters_olive.internode.image_texture = "plugins/plantarchitecture/assets/textures/OliveBark.jpg";
1783 phytomer_parameters_olive.internode.max_floral_buds_per_petiole = 3;
1784
1785 phytomer_parameters_olive.petiole.petioles_per_internode = 2;
1786 phytomer_parameters_olive.petiole.pitch.uniformDistribution(-40, -20);
1787 phytomer_parameters_olive.petiole.taper = 0.1;
1788 phytomer_parameters_olive.petiole.curvature = 0;
1789 phytomer_parameters_olive.petiole.length = 0.01;
1790 phytomer_parameters_olive.petiole.radius = 0.0005;
1791 phytomer_parameters_olive.petiole.length_segments = 1;
1792 phytomer_parameters_olive.petiole.radial_subdivisions = 3;
1793 phytomer_parameters_olive.petiole.color = make_RGBcolor(0.61, 0.5, 0.24);
1794
1795 phytomer_parameters_olive.leaf.leaves_per_petiole = 1;
1796 phytomer_parameters_olive.leaf.prototype_scale = 0.06;
1797 phytomer_parameters_olive.leaf.prototype = leaf_prototype;
1798
1799 phytomer_parameters_olive.peduncle.length = 0.065;
1800 phytomer_parameters_olive.peduncle.radius = 0.001;
1801 phytomer_parameters_olive.peduncle.pitch = 60;
1802 phytomer_parameters_olive.peduncle.roll = 0;
1803 phytomer_parameters_olive.peduncle.length_segments = 1;
1804 phytomer_parameters_olive.peduncle.color = make_RGBcolor(0.7, 0.72, 0.7);
1805
1806 phytomer_parameters_olive.inflorescence.flowers_per_peduncle = 10;
1807 phytomer_parameters_olive.inflorescence.flower_offset = 0.13;
1808 phytomer_parameters_olive.inflorescence.pitch.uniformDistribution(80, 100);
1809 phytomer_parameters_olive.inflorescence.roll.uniformDistribution(0, 360);
1810 phytomer_parameters_olive.inflorescence.flower_prototype_scale = 0.01;
1811 // phytomer_parameters_olive.inflorescence.flower_prototype_function = OliveFlowerPrototype;
1812 phytomer_parameters_olive.inflorescence.fruit_prototype_scale = 0.025;
1813 phytomer_parameters_olive.inflorescence.fruit_prototype_function = OliveFruitPrototype;
1814
1815 // ---- Shoot Parameters ---- //
1816
1817 // Trunk
1818 ShootParameters shoot_parameters_trunk(context_ptr->getRandomGenerator());
1819 shoot_parameters_trunk.phytomer_parameters = phytomer_parameters_olive;
1820 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
1821 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.015;
1822 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 20;
1823 shoot_parameters_trunk.max_nodes = 20;
1824 shoot_parameters_trunk.girth_area_factor = 3.f;
1825 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
1826 shoot_parameters_trunk.vegetative_bud_break_time = 0;
1827 shoot_parameters_trunk.tortuosity = 1;
1828 shoot_parameters_trunk.internode_length_max = 0.05;
1829 shoot_parameters_trunk.internode_length_decay_rate = 0;
1830 shoot_parameters_trunk.defineChildShootTypes({"scaffold"}, {1});
1831
1832 // Proleptic shoots
1833 ShootParameters shoot_parameters_proleptic(context_ptr->getRandomGenerator());
1834 shoot_parameters_proleptic.phytomer_parameters = phytomer_parameters_olive;
1835 // shoot_parameters_proleptic.phytomer_parameters.phytomer_creation_function = OlivePhytomerCreationFunction;
1836 shoot_parameters_proleptic.phytomer_parameters.phytomer_callback_function = OlivePhytomerCallbackFunction;
1837 shoot_parameters_proleptic.max_nodes.uniformDistribution(16, 24);
1838 shoot_parameters_proleptic.max_nodes_per_season.uniformDistribution(8, 12);
1839 shoot_parameters_proleptic.phyllochron_min = 2.0;
1840 shoot_parameters_proleptic.elongation_rate_max = 0.25;
1841 shoot_parameters_proleptic.girth_area_factor = 5.f;
1842 shoot_parameters_proleptic.vegetative_bud_break_probability_min = 0.025;
1843 shoot_parameters_proleptic.vegetative_bud_break_probability_decay_rate = 1.0;
1844 shoot_parameters_proleptic.vegetative_bud_break_time = 30;
1845 shoot_parameters_proleptic.gravitropic_curvature.uniformDistribution(550, 650);
1846 shoot_parameters_proleptic.tortuosity = 5;
1847 shoot_parameters_proleptic.insertion_angle_tip.uniformDistribution(35, 40);
1848 shoot_parameters_proleptic.insertion_angle_decay_rate = 2;
1849 shoot_parameters_proleptic.internode_length_max = 0.05;
1850 shoot_parameters_proleptic.internode_length_min = 0.03;
1851 shoot_parameters_proleptic.internode_length_decay_rate = 0.004;
1852 shoot_parameters_proleptic.fruit_set_probability = 0.25;
1853 shoot_parameters_proleptic.flower_bud_break_probability = 0.25;
1854 shoot_parameters_proleptic.max_terminal_floral_buds = 4;
1855 shoot_parameters_proleptic.flowers_require_dormancy = true;
1856 shoot_parameters_proleptic.growth_requires_dormancy = true;
1857 shoot_parameters_proleptic.determinate_shoot_growth = false;
1858 shoot_parameters_proleptic.defineChildShootTypes({"proleptic"}, {1.0});
1859
1860 // Main scaffolds
1861 ShootParameters shoot_parameters_scaffold = shoot_parameters_proleptic;
1862 shoot_parameters_scaffold.phytomer_parameters.internode.radial_subdivisions = 10;
1863 shoot_parameters_scaffold.max_nodes = 30;
1864 shoot_parameters_scaffold.max_nodes_per_season = 10;
1865 shoot_parameters_scaffold.gravitropic_curvature = 700;
1866 shoot_parameters_scaffold.internode_length_max = 0.04;
1867 shoot_parameters_scaffold.tortuosity = 3;
1868 shoot_parameters_scaffold.defineChildShootTypes({"proleptic"}, {1.0});
1869
1870 defineShootType("trunk", shoot_parameters_trunk);
1871 defineShootType("scaffold", shoot_parameters_scaffold);
1872 defineShootType("proleptic", shoot_parameters_proleptic);
1873}
1874
1875uint PlantArchitecture::buildOliveTree(const helios::vec3 &base_position) {
1876
1877 if (shoot_types.empty()) {
1878 // automatically initialize olive tree shoots
1879 initializeOliveTreeShoots();
1880 }
1881
1882 uint plantID = addPlantInstance(base_position, 0);
1883
1884 uint uID_trunk = addBaseStemShoot(plantID, 19, make_AxisRotation(context_ptr->randu(0.f, 0.025f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)),
1885 shoot_types.at("trunk").phytomer_parameters.internode.radius_initial.val(), 0.01, 1.f, 1.f, 0, "trunk");
1886 appendPhytomerToShoot(plantID, uID_trunk, shoot_types.at("trunk").phytomer_parameters, 0, 0.01, 1, 1);
1887
1888 plant_instances.at(plantID).shoot_tree.at(uID_trunk)->meristem_is_alive = false;
1889
1890 auto phytomers = plant_instances.at(plantID).shoot_tree.at(uID_trunk)->phytomers;
1891 for (const auto &phytomer: phytomers) {
1892 phytomer->removeLeaf();
1893 phytomer->setVegetativeBudState(BUD_DEAD);
1894 phytomer->setFloralBudState(BUD_DEAD);
1895 }
1896
1897 uint Nscaffolds = 4; // context_ptr->randu(4,5);
1898
1899 for (int i = 0; i < Nscaffolds; i++) {
1900 float pitch = context_ptr->randu(deg2rad(30), deg2rad(35));
1901 uint uID_shoot = addChildShoot(plantID, uID_trunk, getShootNodeCount(plantID, uID_trunk) - i - 1, context_ptr->randu(5, 7), make_AxisRotation(pitch, (float(i) + context_ptr->randu(-0.2f, 0.2f)) / float(Nscaffolds) * 2 * M_PI, 0), 0.007,
1902 shoot_types.at("scaffold").internode_length_max.val(), 1.f, 1.f, 0.5, "scaffold", 0);
1903 }
1904
1905 makePlantDormant(plantID);
1906
1907 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 20, 200, 600, true);
1908 plant_instances.at(plantID).max_age = 1825;
1909
1910 return plantID;
1911}
1912
1913void PlantArchitecture::initializePistachioTreeShoots() {
1914
1915 // ---- Leaf Prototype ---- //
1916
1917 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
1918 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/PistachioLeaf.png";
1919 leaf_prototype.leaf_aspect_ratio = 0.6f;
1920 leaf_prototype.midrib_fold_fraction = 0.;
1921 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.4, 0.4);
1922 leaf_prototype.lateral_curvature = 0.;
1923 leaf_prototype.wave_period = 0.3f;
1924 leaf_prototype.wave_amplitude = 0.1f;
1925 leaf_prototype.subdivisions = 3;
1926 leaf_prototype.unique_prototypes = 5;
1927
1928 // ---- Phytomer Parameters ---- //
1929
1930 PhytomerParameters phytomer_parameters_pistachio(context_ptr->getRandomGenerator());
1931
1932 phytomer_parameters_pistachio.internode.pitch = 0;
1933 phytomer_parameters_pistachio.internode.phyllotactic_angle.uniformDistribution(160, 200);
1934 phytomer_parameters_pistachio.internode.radius_initial = 0.002;
1935 phytomer_parameters_pistachio.internode.length_segments = 1;
1936 phytomer_parameters_pistachio.internode.image_texture = "plugins/plantarchitecture/assets/textures/OliveBark.jpg";
1937 phytomer_parameters_pistachio.internode.max_floral_buds_per_petiole = 3;
1938
1939 phytomer_parameters_pistachio.petiole.petioles_per_internode = 2;
1940 phytomer_parameters_pistachio.petiole.pitch.uniformDistribution(-60, -45);
1941 phytomer_parameters_pistachio.petiole.taper = 0.1;
1942 phytomer_parameters_pistachio.petiole.curvature.uniformDistribution(-800, 800);
1943 phytomer_parameters_pistachio.petiole.length = 0.075;
1944 phytomer_parameters_pistachio.petiole.radius = 0.001;
1945 phytomer_parameters_pistachio.petiole.length_segments = 1;
1946 phytomer_parameters_pistachio.petiole.radial_subdivisions = 3;
1947 phytomer_parameters_pistachio.petiole.color = make_RGBcolor(0.6, 0.6, 0.4);
1948
1949 phytomer_parameters_pistachio.leaf.leaves_per_petiole = 3;
1950 phytomer_parameters_pistachio.leaf.prototype_scale = 0.08;
1951 phytomer_parameters_pistachio.leaf.leaflet_offset = 0.3;
1952 phytomer_parameters_pistachio.leaf.leaflet_scale = 0.75;
1953 phytomer_parameters_pistachio.leaf.pitch.uniformDistribution(-20, 20);
1954 phytomer_parameters_pistachio.leaf.roll.uniformDistribution(-20, 20);
1955 phytomer_parameters_pistachio.leaf.prototype = leaf_prototype;
1956
1957 phytomer_parameters_pistachio.peduncle.length = 0.1;
1958 phytomer_parameters_pistachio.peduncle.radius = 0.001;
1959 phytomer_parameters_pistachio.peduncle.pitch = 60;
1960 phytomer_parameters_pistachio.peduncle.roll = 0;
1961 phytomer_parameters_pistachio.peduncle.length_segments = 1;
1962 phytomer_parameters_pistachio.peduncle.curvature.uniformDistribution(500, 900);
1963 phytomer_parameters_pistachio.peduncle.color = make_RGBcolor(0.7, 0.72, 0.7);
1964
1965 phytomer_parameters_pistachio.inflorescence.flowers_per_peduncle = 16;
1966 phytomer_parameters_pistachio.inflorescence.flower_offset = 0.08;
1967 phytomer_parameters_pistachio.inflorescence.pitch.uniformDistribution(50, 70);
1968 phytomer_parameters_pistachio.inflorescence.roll.uniformDistribution(0, 360);
1969 phytomer_parameters_pistachio.inflorescence.flower_prototype_scale = 0.025;
1970 // phytomer_parameters_pistachio.inflorescence.flower_prototype_function = PistachioFlowerPrototype;
1971 phytomer_parameters_pistachio.inflorescence.fruit_prototype_scale = 0.025;
1972 phytomer_parameters_pistachio.inflorescence.fruit_prototype_function = PistachioFruitPrototype;
1973
1974 // ---- Shoot Parameters ---- //
1975
1976 // Trunk
1977 ShootParameters shoot_parameters_trunk(context_ptr->getRandomGenerator());
1978 shoot_parameters_trunk.phytomer_parameters = phytomer_parameters_pistachio;
1979 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 180;
1980 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.015;
1981 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 20;
1982 shoot_parameters_trunk.max_nodes = 20;
1983 shoot_parameters_trunk.girth_area_factor = 3.f;
1984 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
1985 shoot_parameters_trunk.vegetative_bud_break_time = 0;
1986 shoot_parameters_trunk.tortuosity = 1;
1987 shoot_parameters_trunk.internode_length_max = 0.05;
1988 shoot_parameters_trunk.internode_length_decay_rate = 0;
1989 shoot_parameters_trunk.defineChildShootTypes({"proleptic"}, {1});
1990
1991 // Proleptic shoots
1992 ShootParameters shoot_parameters_proleptic(context_ptr->getRandomGenerator());
1993 shoot_parameters_proleptic.phytomer_parameters = phytomer_parameters_pistachio;
1994 shoot_parameters_proleptic.phytomer_parameters.phytomer_creation_function = PistachioPhytomerCreationFunction;
1995 shoot_parameters_proleptic.phytomer_parameters.phytomer_callback_function = PistachioPhytomerCallbackFunction;
1996 shoot_parameters_proleptic.max_nodes.uniformDistribution(16, 24);
1997 shoot_parameters_proleptic.max_nodes_per_season.uniformDistribution(8, 12);
1998 shoot_parameters_proleptic.phyllochron_min = 2.0;
1999 shoot_parameters_proleptic.elongation_rate_max = 0.25;
2000 shoot_parameters_proleptic.girth_area_factor = 8.f;
2001 shoot_parameters_proleptic.vegetative_bud_break_probability_min = 0.025;
2002 shoot_parameters_proleptic.vegetative_bud_break_probability_decay_rate = 0.7;
2003 shoot_parameters_proleptic.vegetative_bud_break_time = 0;
2004 shoot_parameters_proleptic.gravitropic_curvature = 500;
2005 shoot_parameters_proleptic.tortuosity = 10;
2006 shoot_parameters_proleptic.insertion_angle_tip.uniformDistribution(45, 55);
2007 shoot_parameters_proleptic.insertion_angle_decay_rate = 10;
2008 shoot_parameters_proleptic.internode_length_max = 0.06;
2009 shoot_parameters_proleptic.internode_length_min = 0.03;
2010 shoot_parameters_proleptic.internode_length_decay_rate = 0.005;
2011 shoot_parameters_proleptic.fruit_set_probability = 0.35;
2012 shoot_parameters_proleptic.flower_bud_break_probability = 0.35;
2013 shoot_parameters_proleptic.max_terminal_floral_buds = 4;
2014 shoot_parameters_proleptic.flowers_require_dormancy = true;
2015 shoot_parameters_proleptic.growth_requires_dormancy = true;
2016 shoot_parameters_proleptic.determinate_shoot_growth = false;
2017
2018 defineShootType("trunk", shoot_parameters_trunk);
2019 defineShootType("proleptic", shoot_parameters_proleptic);
2020}
2021
2022uint PlantArchitecture::buildPistachioTree(const helios::vec3 &base_position) {
2023
2024 if (shoot_types.empty()) {
2025 // automatically initialize pistachio tree shoots
2026 initializePistachioTreeShoots();
2027 }
2028
2029 uint plantID = addPlantInstance(base_position, 0);
2030
2031 uint uID_trunk = addBaseStemShoot(plantID, 19, make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)),
2032 shoot_types.at("trunk").phytomer_parameters.internode.radius_initial.val(), 0.05, 1.f, 1.f, 0, "trunk");
2033 appendPhytomerToShoot(plantID, uID_trunk, shoot_types.at("trunk").phytomer_parameters, 0, 0.01, 1, 1);
2034
2035 plant_instances.at(plantID).shoot_tree.at(uID_trunk)->meristem_is_alive = false;
2036
2037 auto phytomers = plant_instances.at(plantID).shoot_tree.at(uID_trunk)->phytomers;
2038 for (const auto &phytomer: phytomers) {
2039 phytomer->removeLeaf();
2040 phytomer->setVegetativeBudState(BUD_DEAD);
2041 phytomer->setFloralBudState(BUD_DEAD);
2042 }
2043
2044 uint Nscaffolds = 4; // context_ptr->randu(4,5);
2045
2046 for (int i = 0; i < Nscaffolds; i++) {
2047 float pitch = context_ptr->randu(deg2rad(65), deg2rad(80));
2048 uint uID_shoot = addChildShoot(plantID, uID_trunk, getShootNodeCount(plantID, uID_trunk) - i - 1, 1, make_AxisRotation(pitch, (float(i) + context_ptr->randu(-0.1f, 0.1f)) / float(Nscaffolds) * 2 * M_PI, 0.5 * M_PI), 0.007, 0.06, 1.f, 1.f,
2049 0.5, "proleptic", 0);
2050 }
2051
2052 makePlantDormant(plantID);
2053
2054 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 20, 200, false);
2055 plant_instances.at(plantID).max_age = 1095;
2056
2057 return plantID;
2058}
2059
2060void PlantArchitecture::initializePuncturevineShoots() {
2061
2062 // ---- Leaf Prototype ---- //
2063
2064 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2065 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/PuncturevineLeaf.png";
2066 leaf_prototype.leaf_aspect_ratio = 0.4f;
2067 leaf_prototype.midrib_fold_fraction = 0.2f;
2068 leaf_prototype.longitudinal_curvature = -0.1f;
2069 leaf_prototype.lateral_curvature = 0.4f;
2070 leaf_prototype.subdivisions = 1;
2071 leaf_prototype.unique_prototypes = 1;
2072
2073 // ---- Phytomer Parameters ---- //
2074
2075 PhytomerParameters phytomer_parameters_puncturevine(context_ptr->getRandomGenerator());
2076
2077 phytomer_parameters_puncturevine.internode.pitch.uniformDistribution(0, 15);
2078 phytomer_parameters_puncturevine.internode.phyllotactic_angle = 180.f;
2079 phytomer_parameters_puncturevine.internode.radius_initial = 0.001;
2080 phytomer_parameters_puncturevine.internode.color = make_RGBcolor(0.28, 0.18, 0.13);
2081 phytomer_parameters_puncturevine.internode.length_segments = 1;
2082
2083 phytomer_parameters_puncturevine.petiole.petioles_per_internode = 1;
2084 phytomer_parameters_puncturevine.petiole.pitch.uniformDistribution(60, 80);
2085 phytomer_parameters_puncturevine.petiole.radius = 0.0005;
2086 phytomer_parameters_puncturevine.petiole.length = 0.03;
2087 phytomer_parameters_puncturevine.petiole.taper = 0;
2088 phytomer_parameters_puncturevine.petiole.curvature = 0;
2089 phytomer_parameters_puncturevine.petiole.color = phytomer_parameters_puncturevine.internode.color;
2090 phytomer_parameters_puncturevine.petiole.length_segments = 1;
2091
2092 phytomer_parameters_puncturevine.leaf.leaves_per_petiole = 11;
2093 phytomer_parameters_puncturevine.leaf.pitch.uniformDistribution(0, 40);
2094 phytomer_parameters_puncturevine.leaf.yaw = 30;
2095 phytomer_parameters_puncturevine.leaf.roll.uniformDistribution(-5, 5);
2096 phytomer_parameters_puncturevine.leaf.prototype_scale = 0.012;
2097 phytomer_parameters_puncturevine.leaf.leaflet_offset = 0.18;
2098 phytomer_parameters_puncturevine.leaf.leaflet_scale = 1;
2099 phytomer_parameters_puncturevine.leaf.prototype = leaf_prototype;
2100
2101 phytomer_parameters_puncturevine.peduncle.length = 0.001;
2102 phytomer_parameters_puncturevine.peduncle.color = phytomer_parameters_puncturevine.internode.color;
2103
2104 phytomer_parameters_puncturevine.inflorescence.flowers_per_peduncle = 1;
2105 phytomer_parameters_puncturevine.inflorescence.pitch = -90.f;
2106 phytomer_parameters_puncturevine.inflorescence.flower_prototype_function = PuncturevineFlowerPrototype;
2107 phytomer_parameters_puncturevine.inflorescence.flower_prototype_scale = 0.01;
2108
2109 // ---- Shoot Parameters ---- //
2110
2111 ShootParameters shoot_parameters_primary(context_ptr->getRandomGenerator());
2112 shoot_parameters_primary.phytomer_parameters = phytomer_parameters_puncturevine;
2113 shoot_parameters_primary.vegetative_bud_break_probability_min = 0.1;
2114 shoot_parameters_primary.vegetative_bud_break_probability_decay_rate = 1.f;
2115 shoot_parameters_primary.vegetative_bud_break_time = 10;
2116 shoot_parameters_primary.base_roll = 90;
2117 shoot_parameters_primary.phyllochron_min = 1;
2118 shoot_parameters_primary.elongation_rate_max = 0.2;
2119 shoot_parameters_primary.girth_area_factor = 0.f;
2120 shoot_parameters_primary.internode_length_max = 0.02;
2121 shoot_parameters_primary.internode_length_decay_rate = 0;
2122 shoot_parameters_primary.insertion_angle_tip.uniformDistribution(50, 80);
2123 shoot_parameters_primary.flowers_require_dormancy = false;
2124 shoot_parameters_primary.growth_requires_dormancy = false;
2125 shoot_parameters_primary.flower_bud_break_probability = 0.2;
2126 shoot_parameters_primary.determinate_shoot_growth = false;
2127 shoot_parameters_primary.max_nodes = 15;
2128 shoot_parameters_primary.gravitropic_curvature = 50;
2129 shoot_parameters_primary.tortuosity = 0;
2130 shoot_parameters_primary.defineChildShootTypes({"secondary_puncturevine"}, {1.f});
2131
2132 ShootParameters shoot_parameters_base = shoot_parameters_primary;
2133 shoot_parameters_base.phytomer_parameters = phytomer_parameters_puncturevine;
2134 shoot_parameters_base.phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(137.5 - 10, 137.5 + 10);
2135 shoot_parameters_base.phytomer_parameters.internode.pitch = 0;
2136 shoot_parameters_base.phytomer_parameters.petiole.pitch = 0;
2137 shoot_parameters_base.vegetative_bud_break_probability_min = 1;
2138 shoot_parameters_base.vegetative_bud_break_time = 2;
2139 shoot_parameters_base.phyllochron_min = 2;
2140 shoot_parameters_base.elongation_rate_max = 0.15;
2141 shoot_parameters_base.gravitropic_curvature = 0;
2142 shoot_parameters_base.internode_length_max = 0.01;
2143 shoot_parameters_base.internode_length_decay_rate = 0;
2144 shoot_parameters_base.insertion_angle_tip = 90;
2145 shoot_parameters_base.insertion_angle_decay_rate = 0;
2146 shoot_parameters_base.flowers_require_dormancy = false;
2147 shoot_parameters_base.growth_requires_dormancy = false;
2148 shoot_parameters_base.flower_bud_break_probability = 0.0;
2149 shoot_parameters_base.max_nodes.uniformDistribution(3, 5);
2150 shoot_parameters_base.defineChildShootTypes({"primary_puncturevine"}, {1.f});
2151
2152 ShootParameters shoot_parameters_children = shoot_parameters_primary;
2153 shoot_parameters_children.base_roll = 0;
2154
2155 defineShootType("base_puncturevine", shoot_parameters_base);
2156 defineShootType("primary_puncturevine", shoot_parameters_primary);
2157 defineShootType("secondary_puncturevine", shoot_parameters_children);
2158}
2159
2160uint PlantArchitecture::buildPuncturevinePlant(const helios::vec3 &base_position) {
2161
2162 if (shoot_types.empty()) {
2163 // automatically initialize puncturevine plant shoots
2164 initializePuncturevineShoots();
2165 }
2166
2167 uint plantID = addPlantInstance(base_position, 0);
2168
2169 uint uID_stem = addBaseStemShoot(plantID, 3, make_AxisRotation(0, 0.f, 0.f), 0.001, 0.001, 1, 1, 0, "base_puncturevine");
2170
2171 breakPlantDormancy(plantID);
2172
2173 plant_instances.at(plantID).max_age = 45;
2174
2175 setPlantPhenologicalThresholds(plantID, 0, -1, 14, -1, -1, 1000, false);
2176
2177 return plantID;
2178}
2179
2180void PlantArchitecture::initializeEasternRedbudShoots() {
2181
2182 // ---- Leaf Prototype ---- //
2183
2184 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2185 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/RedbudLeaf.png";
2186 leaf_prototype.leaf_aspect_ratio = 1.f;
2187 leaf_prototype.midrib_fold_fraction = 0.2f;
2188 leaf_prototype.longitudinal_curvature = -0.15f;
2189 leaf_prototype.lateral_curvature = -0.1f;
2190 leaf_prototype.wave_period = 0.3f;
2191 leaf_prototype.wave_amplitude = 0.025f;
2192 leaf_prototype.subdivisions = 5;
2193 leaf_prototype.unique_prototypes = 5;
2194 leaf_prototype.leaf_offset = make_vec3(-0.3, 0, 0);
2195
2196 // ---- Phytomer Parameters ---- //
2197
2198 PhytomerParameters phytomer_parameters_redbud(context_ptr->getRandomGenerator());
2199
2200 phytomer_parameters_redbud.internode.pitch = 15;
2201 phytomer_parameters_redbud.internode.phyllotactic_angle.uniformDistribution(170, 190);
2202 phytomer_parameters_redbud.internode.radius_initial = 0.0015;
2203 phytomer_parameters_redbud.internode.image_texture = "plugins/plantarchitecture/assets/textures/WesternRedbudBark.jpg";
2204 phytomer_parameters_redbud.internode.color.scale(0.3);
2205 phytomer_parameters_redbud.internode.length_segments = 1;
2206 phytomer_parameters_redbud.internode.max_floral_buds_per_petiole = 5;
2207
2208 phytomer_parameters_redbud.petiole.petioles_per_internode = 1;
2209 phytomer_parameters_redbud.petiole.color = make_RGBcolor(0.65, 0.52, 0.39);
2210 phytomer_parameters_redbud.petiole.pitch.uniformDistribution(20, 40);
2211 phytomer_parameters_redbud.petiole.radius = 0.002;
2212 phytomer_parameters_redbud.petiole.length = 0.075;
2213 phytomer_parameters_redbud.petiole.taper = 0;
2214 phytomer_parameters_redbud.petiole.curvature = 0;
2215 phytomer_parameters_redbud.petiole.length_segments = 1;
2216
2217 phytomer_parameters_redbud.leaf.leaves_per_petiole = 1;
2218 phytomer_parameters_redbud.leaf.pitch.uniformDistribution(-110, -80);
2219 phytomer_parameters_redbud.leaf.yaw = 0;
2220 phytomer_parameters_redbud.leaf.roll.uniformDistribution(-5, 5);
2221 phytomer_parameters_redbud.leaf.prototype_scale = 0.1;
2222 phytomer_parameters_redbud.leaf.prototype = leaf_prototype;
2223
2224 phytomer_parameters_redbud.peduncle.length = 0.02;
2225 phytomer_parameters_redbud.peduncle.pitch.uniformDistribution(50, 90);
2226 phytomer_parameters_redbud.peduncle.color = make_RGBcolor(0.32, 0.05, 0.13);
2227
2228 phytomer_parameters_redbud.inflorescence.flowers_per_peduncle = 1;
2229 phytomer_parameters_redbud.inflorescence.pitch = 0;
2230 phytomer_parameters_redbud.inflorescence.flower_prototype_function = RedbudFlowerPrototype;
2231 phytomer_parameters_redbud.inflorescence.flower_prototype_scale = 0.04;
2232 phytomer_parameters_redbud.inflorescence.fruit_prototype_function = RedbudFruitPrototype;
2233 phytomer_parameters_redbud.inflorescence.fruit_prototype_scale = 0.1;
2234 phytomer_parameters_redbud.inflorescence.fruit_gravity_factor_fraction = 0.7;
2235
2236 phytomer_parameters_redbud.phytomer_creation_function = RedbudPhytomerCreationFunction;
2237 phytomer_parameters_redbud.phytomer_callback_function = RedbudPhytomerCallbackFunction;
2238
2239 // ---- Shoot Parameters ---- //
2240
2241 ShootParameters shoot_parameters_main(context_ptr->getRandomGenerator());
2242 shoot_parameters_main.phytomer_parameters = phytomer_parameters_redbud;
2243 shoot_parameters_main.vegetative_bud_break_probability_min = 1.0;
2244 shoot_parameters_main.vegetative_bud_break_time = 2;
2245 shoot_parameters_main.phyllochron_min = 2;
2246 shoot_parameters_main.elongation_rate_max = 0.1;
2247 shoot_parameters_main.girth_area_factor = 4.f;
2248 shoot_parameters_main.gravitropic_curvature = 300;
2249 shoot_parameters_main.tortuosity = 5;
2250 shoot_parameters_main.internode_length_max = 0.04;
2251 shoot_parameters_main.internode_length_decay_rate = 0.005;
2252 shoot_parameters_main.internode_length_min = 0.01;
2253 shoot_parameters_main.insertion_angle_tip = 75;
2254 shoot_parameters_main.insertion_angle_decay_rate = 10;
2255 shoot_parameters_main.flowers_require_dormancy = true;
2256 shoot_parameters_main.growth_requires_dormancy = true;
2257 shoot_parameters_main.determinate_shoot_growth = false;
2258 shoot_parameters_main.max_terminal_floral_buds = 0;
2259 shoot_parameters_main.flower_bud_break_probability = 0.8;
2260 shoot_parameters_main.fruit_set_probability = 0.3;
2261 shoot_parameters_main.max_nodes = 25;
2262 shoot_parameters_main.max_nodes_per_season = 10;
2263 shoot_parameters_main.base_roll = 90;
2264
2265 ShootParameters shoot_parameters_trunk = shoot_parameters_main;
2266 shoot_parameters_trunk.phytomer_parameters.internode.pitch = 0;
2267 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 15;
2268 shoot_parameters_trunk.phytomer_parameters.internode.max_floral_buds_per_petiole = 0;
2269 shoot_parameters_trunk.insertion_angle_tip = 60;
2270 shoot_parameters_trunk.max_nodes = 75;
2271 shoot_parameters_trunk.max_nodes_per_season = 10;
2272 shoot_parameters_trunk.tortuosity = 1.5;
2273 shoot_parameters_trunk.defineChildShootTypes({"eastern_redbud_shoot"}, {1.f});
2274
2275 defineShootType("eastern_redbud_trunk", shoot_parameters_trunk);
2276 defineShootType("eastern_redbud_shoot", shoot_parameters_main);
2277}
2278
2279uint PlantArchitecture::buildEasternRedbudPlant(const helios::vec3 &base_position) {
2280
2281 if (shoot_types.empty()) {
2282 // automatically initialize redbud plant shoots
2283 initializeEasternRedbudShoots();
2284 }
2285
2286 uint plantID = addPlantInstance(base_position, 0);
2287
2288 uint uID_stem = addBaseStemShoot(plantID, 16, make_AxisRotation(context_ptr->randu(0, 0.1 * M_PI), context_ptr->randu(0, 2 * M_PI), context_ptr->randu(0, 2 * M_PI)), 0.0075, 0.05, 1, 1, 0.4, "eastern_redbud_trunk");
2289
2290 makePlantDormant(plantID);
2291 breakPlantDormancy(plantID);
2292
2293 // leave four vegetative buds on the trunk and remove the rest
2294 for (auto &phytomer: this->plant_instances.at(plantID).shoot_tree.at(uID_stem)->phytomers) {
2295 if (phytomer->shoot_index.x < 12) {
2296 for (auto &petiole: phytomer->axillary_vegetative_buds) {
2297 for (auto &vbud: petiole) {
2298 phytomer->setVegetativeBudState(BUD_DEAD, vbud);
2299 }
2300 }
2301 }
2302 }
2303
2304 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 30, 200, false);
2305
2306 plant_instances.at(plantID).max_age = 1460;
2307
2308 return plantID;
2309}
2310
2311void PlantArchitecture::initializeRiceShoots() {
2312
2313 // ---- Leaf Prototype ---- //
2314
2315 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2316 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SorghumLeaf.png";
2317 leaf_prototype.leaf_aspect_ratio = 0.06f;
2318 leaf_prototype.midrib_fold_fraction = 0.3f;
2319 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.2, 0);
2320 leaf_prototype.lateral_curvature = -0.3;
2321 leaf_prototype.wave_period = 0.1f;
2322 leaf_prototype.wave_amplitude = 0.1f;
2323 leaf_prototype.subdivisions = 20;
2324 leaf_prototype.unique_prototypes = 10;
2325
2326 // ---- Phytomer Parameters ---- //
2327
2328 PhytomerParameters phytomer_parameters_rice(context_ptr->getRandomGenerator());
2329
2330 phytomer_parameters_rice.internode.pitch = 0;
2331 phytomer_parameters_rice.internode.phyllotactic_angle.uniformDistribution(67, 77);
2332 phytomer_parameters_rice.internode.radius_initial = 0.001;
2333 phytomer_parameters_rice.internode.color = make_RGBcolor(0.27, 0.31, 0.16);
2334 phytomer_parameters_rice.internode.length_segments = 1;
2335 phytomer_parameters_rice.internode.radial_subdivisions = 6;
2336 phytomer_parameters_rice.internode.max_floral_buds_per_petiole = 0;
2337 phytomer_parameters_rice.internode.max_vegetative_buds_per_petiole = 0;
2338
2339 phytomer_parameters_rice.petiole.petioles_per_internode = 1;
2340 phytomer_parameters_rice.petiole.pitch.uniformDistribution(-40, 0);
2341 phytomer_parameters_rice.petiole.radius = 0.0;
2342 phytomer_parameters_rice.petiole.length = 0.01;
2343 phytomer_parameters_rice.petiole.taper = 0;
2344 phytomer_parameters_rice.petiole.curvature = 0;
2345 phytomer_parameters_rice.petiole.length_segments = 1;
2346
2347 phytomer_parameters_rice.leaf.leaves_per_petiole = 1;
2348 phytomer_parameters_rice.leaf.pitch = 0;
2349 phytomer_parameters_rice.leaf.yaw = 0;
2350 phytomer_parameters_rice.leaf.roll = 0;
2351 phytomer_parameters_rice.leaf.prototype_scale = 0.15;
2352 phytomer_parameters_rice.leaf.prototype = leaf_prototype;
2353
2354 phytomer_parameters_rice.peduncle.pitch = 0;
2355 phytomer_parameters_rice.peduncle.length.uniformDistribution(0.14, 0.18);
2356 phytomer_parameters_rice.peduncle.radius = 0.0005;
2357 phytomer_parameters_rice.peduncle.color = phytomer_parameters_rice.internode.color;
2358 phytomer_parameters_rice.peduncle.curvature.uniformDistribution(-800, -50);
2359 phytomer_parameters_rice.peduncle.radial_subdivisions = 6;
2360 phytomer_parameters_rice.peduncle.length_segments = 8;
2361
2362 phytomer_parameters_rice.inflorescence.flowers_per_peduncle = 60;
2363 phytomer_parameters_rice.inflorescence.pitch.uniformDistribution(20, 25);
2364 phytomer_parameters_rice.inflorescence.roll = 0;
2365 phytomer_parameters_rice.inflorescence.fruit_prototype_scale = 0.008;
2366 phytomer_parameters_rice.inflorescence.flower_offset = 0.012;
2367 phytomer_parameters_rice.inflorescence.fruit_prototype_function = RiceSpikePrototype;
2368
2369 // phytomer_parameters_rice.phytomer_creation_function = RicePhytomerCreationFunction;
2370
2371 // ---- Shoot Parameters ---- //
2372
2373 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
2374 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters_rice;
2375 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0;
2376 shoot_parameters_mainstem.flower_bud_break_probability = 1;
2377 shoot_parameters_mainstem.phyllochron_min = 2;
2378 shoot_parameters_mainstem.elongation_rate_max = 0.1;
2379 shoot_parameters_mainstem.girth_area_factor = 5.f;
2380 shoot_parameters_mainstem.gravitropic_curvature.uniformDistribution(-1000, -400);
2381 shoot_parameters_mainstem.internode_length_max = 0.0075;
2382 shoot_parameters_mainstem.internode_length_decay_rate = 0;
2383 shoot_parameters_mainstem.flowers_require_dormancy = false;
2384 shoot_parameters_mainstem.growth_requires_dormancy = false;
2385 shoot_parameters_mainstem.determinate_shoot_growth = false;
2386 shoot_parameters_mainstem.fruit_set_probability = 1.0;
2387 shoot_parameters_mainstem.defineChildShootTypes({"mainstem"}, {1.0});
2388 shoot_parameters_mainstem.max_nodes = 30;
2389 shoot_parameters_mainstem.max_terminal_floral_buds = 5;
2390
2391 defineShootType("mainstem", shoot_parameters_mainstem);
2392}
2393
2394uint PlantArchitecture::buildRicePlant(const helios::vec3 &base_position) {
2395
2396 if (shoot_types.empty()) {
2397 // automatically initialize rice plant shoots
2398 initializeRiceShoots();
2399 }
2400
2401 uint plantID = addPlantInstance(base_position, 0);
2402
2403 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(context_ptr->randu(0.f, 0.1f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)), 0.001, 0.0075, 0.01, 0.01, 0, "mainstem");
2404
2405 breakPlantDormancy(plantID);
2406
2407 setPlantPhenologicalThresholds(plantID, 0, -1, -1, 4, 10, 1000, false);
2408
2409 plant_instances.at(plantID).max_age = 365;
2410
2411 return plantID;
2412}
2413
2414void PlantArchitecture::initializeButterLettuceShoots() {
2415
2416 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2417 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/RomaineLettuceLeaf.png";
2418 leaf_prototype.leaf_aspect_ratio = 0.85f;
2419 leaf_prototype.midrib_fold_fraction = 0.2f;
2420 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.2, 0.05);
2421 leaf_prototype.lateral_curvature = -0.4f;
2422 leaf_prototype.wave_period.uniformDistribution(0.15, 0.25);
2423 leaf_prototype.wave_amplitude.uniformDistribution(0.05, 0.1);
2424 leaf_prototype.subdivisions = 30;
2425 leaf_prototype.unique_prototypes = 10;
2426
2427 // ---- Phytomer Parameters ---- //
2428
2429 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
2430
2431 phytomer_parameters.internode.pitch = 0;
2432 phytomer_parameters.internode.phyllotactic_angle = 137.5;
2433 phytomer_parameters.internode.radius_initial = 0.02;
2434 phytomer_parameters.internode.color = make_RGBcolor(0.402, 0.423, 0.413);
2435 phytomer_parameters.internode.length_segments = 1;
2436 phytomer_parameters.internode.radial_subdivisions = 10;
2437
2438 phytomer_parameters.petiole.petioles_per_internode = 1;
2439 phytomer_parameters.petiole.pitch.uniformDistribution(0, 30);
2440 phytomer_parameters.petiole.radius = 0.001;
2441 phytomer_parameters.petiole.length = 0.001;
2442 phytomer_parameters.petiole.length_segments = 1;
2443 phytomer_parameters.petiole.radial_subdivisions = 3;
2444 phytomer_parameters.petiole.color = RGB::red;
2445
2446 phytomer_parameters.leaf.leaves_per_petiole = 1;
2447 phytomer_parameters.leaf.pitch = 10;
2448 phytomer_parameters.leaf.yaw = 0;
2449 phytomer_parameters.leaf.roll = 0;
2450 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.15, 0.25);
2451 phytomer_parameters.leaf.prototype = leaf_prototype;
2452
2453 phytomer_parameters.phytomer_creation_function = ButterLettucePhytomerCreationFunction;
2454
2455 // ---- Shoot Parameters ---- //
2456
2457 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
2458 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters;
2459 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0;
2460 shoot_parameters_mainstem.phyllochron_min = 2;
2461 shoot_parameters_mainstem.elongation_rate_max = 0.15;
2462 shoot_parameters_mainstem.girth_area_factor = 0.f;
2463 shoot_parameters_mainstem.gravitropic_curvature = 10;
2464 shoot_parameters_mainstem.internode_length_max = 0.001;
2465 shoot_parameters_mainstem.internode_length_decay_rate = 0;
2466 shoot_parameters_mainstem.flowers_require_dormancy = false;
2467 shoot_parameters_mainstem.growth_requires_dormancy = false;
2468 shoot_parameters_mainstem.flower_bud_break_probability = 0.0;
2469 shoot_parameters_mainstem.max_nodes = 25;
2470
2471 defineShootType("mainstem", shoot_parameters_mainstem);
2472}
2473
2474uint PlantArchitecture::buildButterLettucePlant(const helios::vec3 &base_position) {
2475
2476 if (shoot_types.empty()) {
2477 // automatically initialize lettuce plant shoots
2478 initializeButterLettuceShoots();
2479 }
2480
2481 uint plantID = addPlantInstance(base_position, 0);
2482
2483 uint uID_stem = addBaseStemShoot(plantID, 3, make_AxisRotation(context_ptr->randu(0.f, 0.03f * M_PI), 0.f, context_ptr->randu(0.f, 2.f * M_PI)), 0.005, 0.001, 1, 1, 0, "mainstem");
2484
2485 breakPlantDormancy(plantID);
2486
2487 setPlantPhenologicalThresholds(plantID, 0, -1, -1, -1, -1, 1000, false);
2488
2489 plant_instances.at(plantID).max_age = 365;
2490
2491 return plantID;
2492}
2493
2494void PlantArchitecture::initializeSorghumShoots() {
2495
2496 // ---- Leaf Prototype ---- //
2497
2498 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2499 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SorghumLeaf.png";
2500 leaf_prototype.leaf_aspect_ratio = 0.2f;
2501 leaf_prototype.midrib_fold_fraction = 0.3f;
2502 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.4, -0.2);
2503 leaf_prototype.lateral_curvature = -0.3f;
2504 leaf_prototype.petiole_roll = 0.04f;
2505 leaf_prototype.wave_period = 0.1f;
2506 leaf_prototype.wave_amplitude = 0.1f;
2507 leaf_prototype.leaf_buckle_length.uniformDistribution(0.4, 0.6);
2508 leaf_prototype.leaf_buckle_angle.uniformDistribution(45, 55);
2509 leaf_prototype.subdivisions = 50;
2510 leaf_prototype.unique_prototypes = 10;
2511
2512 // ---- Phytomer Parameters ---- //
2513
2514 PhytomerParameters phytomer_parameters_sorghum(context_ptr->getRandomGenerator());
2515
2516 phytomer_parameters_sorghum.internode.pitch = 0;
2517 phytomer_parameters_sorghum.internode.phyllotactic_angle.uniformDistribution(170, 190);
2518 phytomer_parameters_sorghum.internode.radius_initial = 0.003;
2519 phytomer_parameters_sorghum.internode.color = make_RGBcolor(0.09, 0.13, 0.06);
2520 phytomer_parameters_sorghum.internode.length_segments = 2;
2521 phytomer_parameters_sorghum.internode.radial_subdivisions = 10;
2522 phytomer_parameters_sorghum.internode.max_floral_buds_per_petiole = 0;
2523 phytomer_parameters_sorghum.internode.max_vegetative_buds_per_petiole = 0;
2524
2525 phytomer_parameters_sorghum.petiole.petioles_per_internode = 1;
2526 phytomer_parameters_sorghum.petiole.pitch.uniformDistribution(-40, -20);
2527 phytomer_parameters_sorghum.petiole.radius = 0.0;
2528 phytomer_parameters_sorghum.petiole.length = 0.05;
2529 phytomer_parameters_sorghum.petiole.taper = 0;
2530 phytomer_parameters_sorghum.petiole.curvature = 0;
2531 phytomer_parameters_sorghum.petiole.length_segments = 1;
2532
2533 phytomer_parameters_sorghum.leaf.leaves_per_petiole = 1;
2534 phytomer_parameters_sorghum.leaf.pitch = 0;
2535 phytomer_parameters_sorghum.leaf.yaw = 0;
2536 phytomer_parameters_sorghum.leaf.roll = 0;
2537 phytomer_parameters_sorghum.leaf.prototype_scale = 0.6;
2538 phytomer_parameters_sorghum.leaf.prototype = leaf_prototype;
2539
2540 phytomer_parameters_sorghum.peduncle.length = 0.3;
2541 phytomer_parameters_sorghum.peduncle.radius = 0.008;
2542 phytomer_parameters_sorghum.peduncle.color = phytomer_parameters_sorghum.internode.color;
2543 phytomer_parameters_sorghum.peduncle.radial_subdivisions = 10;
2544
2545 phytomer_parameters_sorghum.inflorescence.flowers_per_peduncle = 1;
2546 phytomer_parameters_sorghum.inflorescence.pitch = 0;
2547 phytomer_parameters_sorghum.inflorescence.roll = 0;
2548 phytomer_parameters_sorghum.inflorescence.fruit_prototype_scale = 0.18;
2549 phytomer_parameters_sorghum.inflorescence.fruit_prototype_function = SorghumPaniclePrototype;
2550
2551 phytomer_parameters_sorghum.phytomer_creation_function = SorghumPhytomerCreationFunction;
2552
2553 // ---- Shoot Parameters ---- //
2554
2555 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
2556 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters_sorghum;
2557 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0;
2558 shoot_parameters_mainstem.flower_bud_break_probability = 1;
2559 shoot_parameters_mainstem.phyllochron_min = 2;
2560 shoot_parameters_mainstem.elongation_rate_max = 0.1;
2561 shoot_parameters_mainstem.girth_area_factor = 5.f;
2562 shoot_parameters_mainstem.gravitropic_curvature.uniformDistribution(-1000, -400);
2563 shoot_parameters_mainstem.internode_length_max = 0.26;
2564 shoot_parameters_mainstem.internode_length_decay_rate = 0;
2565 shoot_parameters_mainstem.flowers_require_dormancy = false;
2566 shoot_parameters_mainstem.growth_requires_dormancy = false;
2567 shoot_parameters_mainstem.determinate_shoot_growth = false;
2568 shoot_parameters_mainstem.flower_bud_break_probability = 1.0;
2569 shoot_parameters_mainstem.fruit_set_probability = 1.0;
2570 shoot_parameters_mainstem.defineChildShootTypes({"mainstem"}, {1.0});
2571 shoot_parameters_mainstem.max_nodes = 16;
2572 shoot_parameters_mainstem.max_terminal_floral_buds = 1;
2573
2574 defineShootType("mainstem", shoot_parameters_mainstem);
2575}
2576
2577uint PlantArchitecture::buildSorghumPlant(const helios::vec3 &base_position) {
2578
2579 if (shoot_types.empty()) {
2580 // automatically initialize sorghum plant shoots
2581 initializeSorghumShoots();
2582 }
2583
2584 uint plantID = addPlantInstance(base_position - make_vec3(0, 0, 0.025), 0);
2585
2586 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(context_ptr->randu(0.f, 0.075f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)), 0.003, 0.06, 0.01, 0.01, 0, "mainstem");
2587
2588 breakPlantDormancy(plantID);
2589
2590 setPlantPhenologicalThresholds(plantID, 0, -1, -1, 4, 15, 1000, false);
2591
2592 plant_instances.at(plantID).max_age = 365;
2593
2594 return plantID;
2595}
2596
2597void PlantArchitecture::initializeSoybeanShoots() {
2598
2599 // ---- Leaf Prototype ---- //
2600
2601 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2602 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SoybeanLeaf.png";
2603 leaf_prototype.leaf_aspect_ratio = 1.f;
2604 leaf_prototype.midrib_fold_fraction = 0.1f;
2605 leaf_prototype.longitudinal_curvature.uniformDistribution(0.1, 0.2);
2606 leaf_prototype.lateral_curvature = 0.45;
2607 leaf_prototype.subdivisions = 8;
2608 leaf_prototype.unique_prototypes = 5;
2609 leaf_prototype.build_petiolule = true;
2610
2611 PhytomerParameters phytomer_parameters_trifoliate(context_ptr->getRandomGenerator());
2612
2613 phytomer_parameters_trifoliate.internode.pitch = 20;
2614 phytomer_parameters_trifoliate.internode.phyllotactic_angle.uniformDistribution(145, 215);
2615 phytomer_parameters_trifoliate.internode.radius_initial = 0.002;
2616 phytomer_parameters_trifoliate.internode.max_floral_buds_per_petiole = 1;
2617 phytomer_parameters_trifoliate.internode.max_vegetative_buds_per_petiole = 1;
2618 phytomer_parameters_trifoliate.internode.color = make_RGBcolor(0.2, 0.25, 0.05);
2619 phytomer_parameters_trifoliate.internode.length_segments = 5;
2620
2621 phytomer_parameters_trifoliate.petiole.petioles_per_internode = 1;
2622 phytomer_parameters_trifoliate.petiole.pitch.uniformDistribution(15, 40);
2623 phytomer_parameters_trifoliate.petiole.radius = 0.002;
2624 phytomer_parameters_trifoliate.petiole.length.uniformDistribution(0.12, 0.16);
2625 phytomer_parameters_trifoliate.petiole.taper = 0.25;
2626 phytomer_parameters_trifoliate.petiole.curvature.uniformDistribution(-250, 50);
2627 phytomer_parameters_trifoliate.petiole.color = phytomer_parameters_trifoliate.internode.color;
2628 phytomer_parameters_trifoliate.petiole.length_segments = 5;
2629 phytomer_parameters_trifoliate.petiole.radial_subdivisions = 6;
2630
2631 phytomer_parameters_trifoliate.leaf.leaves_per_petiole = 3;
2632 phytomer_parameters_trifoliate.leaf.pitch.uniformDistribution(-30, 10);
2633 phytomer_parameters_trifoliate.leaf.yaw = 10;
2634 phytomer_parameters_trifoliate.leaf.roll.uniformDistribution(-25, 5);
2635 phytomer_parameters_trifoliate.leaf.leaflet_offset = 0.5;
2636 phytomer_parameters_trifoliate.leaf.leaflet_scale = 0.9;
2637 phytomer_parameters_trifoliate.leaf.prototype_scale.uniformDistribution(0.1, 0.14);
2638 phytomer_parameters_trifoliate.leaf.prototype = leaf_prototype;
2639
2640 phytomer_parameters_trifoliate.peduncle.length = 0.01;
2641 phytomer_parameters_trifoliate.peduncle.radius = 0.0005;
2642 phytomer_parameters_trifoliate.peduncle.pitch.uniformDistribution(0, 40);
2643 phytomer_parameters_trifoliate.peduncle.roll = 90;
2644 phytomer_parameters_trifoliate.peduncle.curvature.uniformDistribution(-500, 500);
2645 phytomer_parameters_trifoliate.peduncle.color = phytomer_parameters_trifoliate.internode.color;
2646 phytomer_parameters_trifoliate.peduncle.length_segments = 1;
2647 phytomer_parameters_trifoliate.peduncle.radial_subdivisions = 6;
2648
2649 phytomer_parameters_trifoliate.inflorescence.flowers_per_peduncle.uniformDistribution(1, 4);
2650 phytomer_parameters_trifoliate.inflorescence.flower_offset = 0.2;
2651 phytomer_parameters_trifoliate.inflorescence.pitch.uniformDistribution(50, 70);
2652 phytomer_parameters_trifoliate.inflorescence.roll.uniformDistribution(-20, 20);
2653 phytomer_parameters_trifoliate.inflorescence.flower_prototype_scale = 0.015;
2654 phytomer_parameters_trifoliate.inflorescence.flower_prototype_function = SoybeanFlowerPrototype;
2655 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_scale.uniformDistribution(0.1, 0.12);
2656 phytomer_parameters_trifoliate.inflorescence.fruit_prototype_function = SoybeanFruitPrototype;
2657 phytomer_parameters_trifoliate.inflorescence.fruit_gravity_factor_fraction.uniformDistribution(0.8, 1.0);
2658
2659 PhytomerParameters phytomer_parameters_unifoliate = phytomer_parameters_trifoliate;
2660 phytomer_parameters_unifoliate.internode.pitch = 0;
2661 phytomer_parameters_unifoliate.internode.max_vegetative_buds_per_petiole = 0;
2662 phytomer_parameters_unifoliate.internode.max_floral_buds_per_petiole = 0;
2663 phytomer_parameters_unifoliate.petiole.petioles_per_internode = 2;
2664 phytomer_parameters_unifoliate.petiole.length = 0.01;
2665 phytomer_parameters_unifoliate.petiole.radius = 0.001;
2666 phytomer_parameters_unifoliate.petiole.pitch.uniformDistribution(60, 80);
2667 phytomer_parameters_unifoliate.leaf.leaves_per_petiole = 1;
2668 phytomer_parameters_unifoliate.leaf.prototype_scale = 0.02;
2669 phytomer_parameters_unifoliate.leaf.pitch.uniformDistribution(-10, 10);
2670 phytomer_parameters_unifoliate.leaf.prototype = leaf_prototype;
2671
2672 // ---- Shoot Parameters ---- //
2673
2674 ShootParameters shoot_parameters_trifoliate(context_ptr->getRandomGenerator());
2675 shoot_parameters_trifoliate.phytomer_parameters = phytomer_parameters_trifoliate;
2676 shoot_parameters_trifoliate.phytomer_parameters.phytomer_creation_function = BeanPhytomerCreationFunction;
2677
2678 shoot_parameters_trifoliate.max_nodes = 25;
2679 shoot_parameters_trifoliate.insertion_angle_tip.uniformDistribution(20, 30);
2680 // shoot_parameters_trifoliate.child_insertion_angle_decay_rate = 0; (default)
2681 shoot_parameters_trifoliate.internode_length_max = 0.035;
2682 // shoot_parameters_trifoliate.child_internode_length_min = 0.0; (default)
2683 // shoot_parameters_trifoliate.child_internode_length_decay_rate = 0; (default)
2684 shoot_parameters_trifoliate.base_roll = 90;
2685 shoot_parameters_trifoliate.base_yaw.uniformDistribution(-20, 20);
2686 shoot_parameters_trifoliate.gravitropic_curvature = 400;
2687
2688 shoot_parameters_trifoliate.phyllochron_min = 2;
2689 shoot_parameters_trifoliate.elongation_rate_max = 0.1;
2690 shoot_parameters_trifoliate.girth_area_factor = 2.f;
2691 shoot_parameters_trifoliate.vegetative_bud_break_time = 15;
2692 shoot_parameters_trifoliate.vegetative_bud_break_probability_min = 0.05;
2693 shoot_parameters_trifoliate.vegetative_bud_break_probability_decay_rate = 0.6;
2694 // shoot_parameters_trifoliate.max_terminal_floral_buds = 0; (default)
2695 shoot_parameters_trifoliate.flower_bud_break_probability.uniformDistribution(0.8, 1.0);
2696 shoot_parameters_trifoliate.fruit_set_probability = 0.4;
2697 // shoot_parameters_trifoliate.flowers_require_dormancy = false; (default)
2698 // shoot_parameters_trifoliate.growth_requires_dormancy = false; (default)
2699 // shoot_parameters_trifoliate.determinate_shoot_growth = true; (default)
2700
2701 shoot_parameters_trifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
2702
2703
2704 ShootParameters shoot_parameters_unifoliate = shoot_parameters_trifoliate;
2705 shoot_parameters_unifoliate.phytomer_parameters = phytomer_parameters_unifoliate;
2706 shoot_parameters_unifoliate.max_nodes = 1;
2707 shoot_parameters_unifoliate.flower_bud_break_probability = 0;
2708 shoot_parameters_unifoliate.insertion_angle_tip = 0;
2709 shoot_parameters_unifoliate.insertion_angle_decay_rate = 0;
2710 shoot_parameters_unifoliate.vegetative_bud_break_time = 8;
2711 shoot_parameters_unifoliate.defineChildShootTypes({"trifoliate"}, {1.0});
2712
2713 defineShootType("unifoliate", shoot_parameters_unifoliate);
2714 defineShootType("trifoliate", shoot_parameters_trifoliate);
2715}
2716
2717uint PlantArchitecture::buildSoybeanPlant(const helios::vec3 &base_position) {
2718
2719 if (shoot_types.empty()) {
2720 // automatically initialize bean plant shoots
2721 initializeSoybeanShoots();
2722 }
2723
2724 uint plantID = addPlantInstance(base_position, 0);
2725
2726 AxisRotation base_rotation = make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
2727 uint uID_unifoliate = addBaseStemShoot(plantID, 1, base_rotation, 0.0005, 0.04, 0.01, 0.01, 0, "unifoliate");
2728
2729 appendShoot(plantID, uID_unifoliate, 1, make_AxisRotation(0, 0, 0.5f * M_PI), shoot_types.at("trifoliate").phytomer_parameters.internode.radius_initial.val(), shoot_types.at("trifoliate").internode_length_max.val(), 0.1, 0.1, 0, "trifoliate");
2730
2731 breakPlantDormancy(plantID);
2732
2733 setPlantPhenologicalThresholds(plantID, 0, 40, 5, 5, 30, 1000, false);
2734
2735 plant_instances.at(plantID).max_age = 365;
2736
2737 return plantID;
2738}
2739
2740void PlantArchitecture::initializeStrawberryShoots() {
2741
2742 // ---- Leaf Prototype ---- //
2743
2744 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2745 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/StrawberryLeaf.png";
2746 leaf_prototype.leaf_aspect_ratio = 1.f;
2747 leaf_prototype.midrib_fold_fraction = 0.2f;
2748 leaf_prototype.longitudinal_curvature = 0.15f;
2749 leaf_prototype.lateral_curvature = -0.35f;
2750 leaf_prototype.wave_period = 0.4f;
2751 leaf_prototype.wave_amplitude = 0.03f;
2752 leaf_prototype.subdivisions = 6;
2753 leaf_prototype.unique_prototypes = 10;
2754
2755 // ---- Phytomer Parameters ---- //
2756
2757 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
2758
2759 phytomer_parameters.internode.pitch = 10;
2760 phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(80, 100);
2761 phytomer_parameters.internode.radius_initial = 0.001;
2762 phytomer_parameters.internode.color = make_RGBcolor(0.15, 0.2, 0.1);
2763 phytomer_parameters.internode.length_segments = 1;
2764
2765 phytomer_parameters.petiole.petioles_per_internode = 1;
2766 phytomer_parameters.petiole.pitch.uniformDistribution(10, 45);
2767 phytomer_parameters.petiole.radius = 0.0025;
2768 phytomer_parameters.petiole.length.uniformDistribution(0.15, 0.35);
2769 phytomer_parameters.petiole.taper = 0.5;
2770 phytomer_parameters.petiole.curvature.uniformDistribution(-150, -50);
2771 phytomer_parameters.petiole.color = make_RGBcolor(0.18, 0.23, 0.1);
2772 phytomer_parameters.petiole.length_segments = 5;
2773
2774 phytomer_parameters.leaf.leaves_per_petiole = 3;
2775 phytomer_parameters.leaf.pitch.uniformDistribution(-35, 0);
2776 phytomer_parameters.leaf.yaw = -30;
2777 phytomer_parameters.leaf.roll = -30;
2778 phytomer_parameters.leaf.leaflet_offset = 0.01;
2779 phytomer_parameters.leaf.leaflet_scale = 1.0;
2780 phytomer_parameters.leaf.prototype_scale = 0.12;
2781 phytomer_parameters.leaf.prototype = leaf_prototype;
2782
2783 phytomer_parameters.peduncle.length.uniformDistribution(0.16, 0.2);
2784 phytomer_parameters.peduncle.radius = 0.0018;
2785 phytomer_parameters.peduncle.pitch.uniformDistribution(35, 55);
2786 phytomer_parameters.peduncle.roll = 90;
2787 phytomer_parameters.peduncle.curvature = -150;
2788 phytomer_parameters.peduncle.length_segments = 5;
2789 phytomer_parameters.peduncle.radial_subdivisions = 6;
2790 phytomer_parameters.peduncle.color = phytomer_parameters.petiole.color;
2791
2792 phytomer_parameters.inflorescence.flowers_per_peduncle = 1; //.uniformDistribution(1, 2);
2793 phytomer_parameters.inflorescence.flower_offset = 0.2;
2794 phytomer_parameters.inflorescence.pitch = 70;
2795 phytomer_parameters.inflorescence.roll = 90;
2796 phytomer_parameters.inflorescence.flower_prototype_scale = 0.04;
2797 phytomer_parameters.inflorescence.flower_prototype_function = StrawberryFlowerPrototype;
2798 phytomer_parameters.inflorescence.fruit_prototype_scale = 0.085;
2799 phytomer_parameters.inflorescence.fruit_prototype_function = StrawberryFruitPrototype;
2800 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction = 0.65;
2801
2802 // ---- Shoot Parameters ---- //
2803
2804 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
2805 shoot_parameters.phytomer_parameters = phytomer_parameters;
2806
2807 shoot_parameters.max_nodes = 15;
2808 shoot_parameters.insertion_angle_tip = 40;
2809 shoot_parameters.insertion_angle_decay_rate = 0;
2810 shoot_parameters.internode_length_max = 0.015;
2811 shoot_parameters.internode_length_decay_rate = 0;
2812 shoot_parameters.internode_length_min = 0.0;
2813 shoot_parameters.base_roll = 90;
2814 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
2815 shoot_parameters.gravitropic_curvature.uniformDistribution(-10, 0);
2816 shoot_parameters.tortuosity = 0;
2817
2818 shoot_parameters.phyllochron_min = 2;
2819 shoot_parameters.elongation_rate_max = 0.1;
2820 shoot_parameters.girth_area_factor = 2.f;
2821 shoot_parameters.vegetative_bud_break_time = 15;
2822 shoot_parameters.vegetative_bud_break_probability_min = 0.;
2823 shoot_parameters.vegetative_bud_break_probability_decay_rate = -0.5;
2824 shoot_parameters.flower_bud_break_probability = 1;
2825 shoot_parameters.fruit_set_probability = 0.3;
2826 shoot_parameters.flowers_require_dormancy = false;
2827 shoot_parameters.growth_requires_dormancy = false;
2828 shoot_parameters.determinate_shoot_growth = true;
2829
2830 shoot_parameters.defineChildShootTypes({"mainstem"}, {1.0});
2831
2832 defineShootType("mainstem", shoot_parameters);
2833}
2834
2835uint PlantArchitecture::buildStrawberryPlant(const helios::vec3 &base_position) {
2836
2837 if (shoot_types.empty()) {
2838 // automatically initialize strawberry plant shoots
2839 initializeStrawberryShoots();
2840 }
2841
2842 uint plantID = addPlantInstance(base_position, 0);
2843
2844 AxisRotation base_rotation = make_AxisRotation(0, context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
2845 uint uID_stem = addBaseStemShoot(plantID, 1, base_rotation, 0.001, 0.004, 0.01, 0.01, 0, "mainstem");
2846
2847 breakPlantDormancy(plantID);
2848
2849 setPlantPhenologicalThresholds(plantID, 0, 40, 5, 5, 30, 1000, false);
2850
2851 plant_instances.at(plantID).max_age = 120;
2852
2853 return plantID;
2854}
2855
2856void PlantArchitecture::initializeSugarbeetShoots() {
2857
2858 // ---- Leaf Prototype ---- //
2859
2860 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2861 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SugarbeetLeaf.png";
2862 leaf_prototype.leaf_aspect_ratio = 0.4f;
2863 leaf_prototype.midrib_fold_fraction = 0.1f;
2864 leaf_prototype.longitudinal_curvature = -0.2f;
2865 leaf_prototype.lateral_curvature = -0.4f;
2866 leaf_prototype.petiole_roll = 0.75f;
2867 leaf_prototype.wave_period.uniformDistribution(0.08f, 0.15f);
2868 leaf_prototype.wave_amplitude.uniformDistribution(0.02, 0.04);
2869 leaf_prototype.subdivisions = 20;
2870 ;
2871 leaf_prototype.unique_prototypes = 10;
2872
2873 // ---- Phytomer Parameters ---- //
2874
2875 PhytomerParameters phytomer_parameters_sugarbeet(context_ptr->getRandomGenerator());
2876
2877 phytomer_parameters_sugarbeet.internode.pitch = 0;
2878 phytomer_parameters_sugarbeet.internode.phyllotactic_angle = 137.5;
2879 phytomer_parameters_sugarbeet.internode.radius_initial = 0.005;
2880 phytomer_parameters_sugarbeet.internode.color = make_RGBcolor(0.44, 0.58, 0.19);
2881 phytomer_parameters_sugarbeet.internode.length_segments = 1;
2882 phytomer_parameters_sugarbeet.internode.max_vegetative_buds_per_petiole = 0;
2883 phytomer_parameters_sugarbeet.internode.max_floral_buds_per_petiole = 0;
2884
2885 phytomer_parameters_sugarbeet.petiole.petioles_per_internode = 1;
2886 phytomer_parameters_sugarbeet.petiole.pitch.uniformDistribution(0, 40);
2887 phytomer_parameters_sugarbeet.petiole.radius = 0.005;
2888 phytomer_parameters_sugarbeet.petiole.length.uniformDistribution(0.15, 0.2);
2889 phytomer_parameters_sugarbeet.petiole.taper = 0.6;
2890 phytomer_parameters_sugarbeet.petiole.curvature.uniformDistribution(-300, 100);
2891 phytomer_parameters_sugarbeet.petiole.color = phytomer_parameters_sugarbeet.internode.color;
2892 phytomer_parameters_sugarbeet.petiole.length_segments = 8;
2893
2894 phytomer_parameters_sugarbeet.leaf.leaves_per_petiole = 1;
2895 phytomer_parameters_sugarbeet.leaf.pitch.uniformDistribution(-10, 0);
2896 phytomer_parameters_sugarbeet.leaf.yaw.uniformDistribution(-5, 5);
2897 phytomer_parameters_sugarbeet.leaf.roll.uniformDistribution(-15, 15);
2898 phytomer_parameters_sugarbeet.leaf.prototype_scale.uniformDistribution(0.15, 0.25);
2899 phytomer_parameters_sugarbeet.leaf.prototype = leaf_prototype;
2900
2901 // ---- Shoot Parameters ---- //
2902
2903 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
2904 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters_sugarbeet;
2905 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0;
2906 shoot_parameters_mainstem.phyllochron_min = 2;
2907 shoot_parameters_mainstem.elongation_rate_max = 0.1;
2908 shoot_parameters_mainstem.girth_area_factor = 20.f;
2909 shoot_parameters_mainstem.gravitropic_curvature = 10;
2910 shoot_parameters_mainstem.internode_length_max = 0.001;
2911 shoot_parameters_mainstem.internode_length_decay_rate = 0;
2912 shoot_parameters_mainstem.flowers_require_dormancy = false;
2913 shoot_parameters_mainstem.growth_requires_dormancy = false;
2914 shoot_parameters_mainstem.flower_bud_break_probability = 0.0;
2915 shoot_parameters_mainstem.max_nodes = 30;
2916
2917 defineShootType("mainstem", shoot_parameters_mainstem);
2918}
2919
2920uint PlantArchitecture::buildSugarbeetPlant(const helios::vec3 &base_position) {
2921
2922 if (shoot_types.empty()) {
2923 // automatically initialize sugarbeet plant shoots
2924 initializeSugarbeetShoots();
2925 }
2926
2927 uint plantID = addPlantInstance(base_position, 0);
2928
2929 uint uID_stem = addBaseStemShoot(plantID, 3, make_AxisRotation(context_ptr->randu(0.f, 0.01f * M_PI), 0.f * context_ptr->randu(0.f, 2.f * M_PI), 0.25f * M_PI), 0.005, 0.001, 1, 1, 0, "mainstem");
2930
2931 breakPlantDormancy(plantID);
2932
2933 setPlantPhenologicalThresholds(plantID, 0, -1, -1, -1, -1, 1000, false);
2934
2935 plant_instances.at(plantID).max_age = 365;
2936
2937 return plantID;
2938}
2939
2940void PlantArchitecture::initializeTomatoShoots() {
2941
2942 // ---- Leaf Prototype ---- //
2943
2944 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
2945 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/TomatoLeaf_centered.png";
2946 leaf_prototype.leaf_aspect_ratio = 0.5f;
2947 leaf_prototype.midrib_fold_fraction = 0.1f;
2948 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.45, -0.2f);
2949 leaf_prototype.lateral_curvature = -0.3f;
2950 leaf_prototype.wave_period = 0.35f;
2951 leaf_prototype.wave_amplitude = 0.08f;
2952 leaf_prototype.subdivisions = 6;
2953 leaf_prototype.unique_prototypes = 5;
2954
2955 // ---- Phytomer Parameters ---- //
2956
2957 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
2958
2959 phytomer_parameters.internode.pitch = 10;
2960 phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(140, 220);
2961 phytomer_parameters.internode.radius_initial = 0.001;
2962 phytomer_parameters.internode.color = make_RGBcolor(0.217, 0.275, 0.0571);
2963 phytomer_parameters.internode.length_segments = 1;
2964
2965 phytomer_parameters.petiole.petioles_per_internode = 1;
2966 phytomer_parameters.petiole.pitch.uniformDistribution(45, 60);
2967 phytomer_parameters.petiole.radius = 0.002;
2968 phytomer_parameters.petiole.length = 0.2;
2969 phytomer_parameters.petiole.taper = 0.15;
2970 phytomer_parameters.petiole.curvature.uniformDistribution(-150, -50);
2971 phytomer_parameters.petiole.color = phytomer_parameters.internode.color;
2972 phytomer_parameters.petiole.length_segments = 5;
2973
2974 phytomer_parameters.leaf.leaves_per_petiole = 7;
2975 phytomer_parameters.leaf.pitch.uniformDistribution(-30, 5);
2976 phytomer_parameters.leaf.yaw = 10;
2977 phytomer_parameters.leaf.roll = 0;
2978 phytomer_parameters.leaf.leaflet_offset = 0.15;
2979 phytomer_parameters.leaf.leaflet_scale = 0.7;
2980 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.12, 0.18);
2981 phytomer_parameters.leaf.prototype = leaf_prototype;
2982
2983 phytomer_parameters.peduncle.length = 0.16;
2984 phytomer_parameters.peduncle.radius = 0.0015;
2985 phytomer_parameters.peduncle.pitch = 20;
2986 phytomer_parameters.peduncle.roll = 0;
2987 phytomer_parameters.peduncle.curvature = -700;
2988 phytomer_parameters.peduncle.color = phytomer_parameters.internode.color;
2989 phytomer_parameters.peduncle.length_segments = 5;
2990 phytomer_parameters.peduncle.radial_subdivisions = 8;
2991
2992 phytomer_parameters.inflorescence.flowers_per_peduncle = 8;
2993 phytomer_parameters.inflorescence.flower_offset = 0.15;
2994 phytomer_parameters.inflorescence.pitch = 90;
2995 phytomer_parameters.inflorescence.roll.uniformDistribution(-30, 30);
2996 phytomer_parameters.inflorescence.flower_prototype_scale = 0.03;
2997 phytomer_parameters.inflorescence.flower_prototype_function = TomatoFlowerPrototype;
2998 phytomer_parameters.inflorescence.fruit_prototype_scale = 0.08;
2999 phytomer_parameters.inflorescence.fruit_prototype_function = TomatoFruitPrototype;
3000 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction = 0.5;
3001
3002 // ---- Shoot Parameters ---- //
3003
3004 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
3005 shoot_parameters.phytomer_parameters = phytomer_parameters;
3006 shoot_parameters.phytomer_parameters.phytomer_creation_function = TomatoPhytomerCreationFunction;
3007
3008 shoot_parameters.max_nodes = 16;
3009 shoot_parameters.insertion_angle_tip = 30;
3010 shoot_parameters.insertion_angle_decay_rate = 0;
3011 shoot_parameters.internode_length_max = 0.04;
3012 shoot_parameters.internode_length_min = 0.0;
3013 shoot_parameters.internode_length_decay_rate = 0;
3014 shoot_parameters.base_roll = 90;
3015 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
3016 shoot_parameters.gravitropic_curvature = 150;
3017 shoot_parameters.tortuosity = 3;
3018
3019 shoot_parameters.phyllochron_min = 2;
3020 shoot_parameters.elongation_rate_max = 0.1;
3021 shoot_parameters.girth_area_factor = 2.5f;
3022 shoot_parameters.vegetative_bud_break_time = 30;
3023 shoot_parameters.vegetative_bud_break_probability_min = 0.25;
3024 shoot_parameters.vegetative_bud_break_probability_decay_rate = -0.25;
3025 shoot_parameters.flower_bud_break_probability = 0.2;
3026 shoot_parameters.fruit_set_probability = 0.8;
3027 shoot_parameters.flowers_require_dormancy = false;
3028 shoot_parameters.growth_requires_dormancy = false;
3029 shoot_parameters.determinate_shoot_growth = true;
3030
3031 shoot_parameters.defineChildShootTypes({"mainstem"}, {1.0});
3032
3033 defineShootType("mainstem", shoot_parameters);
3034}
3035
3036uint PlantArchitecture::buildTomatoPlant(const helios::vec3 &base_position) {
3037
3038 if (shoot_types.empty()) {
3039 // automatically initialize tomato plant shoots
3040 initializeTomatoShoots();
3041 }
3042
3043 uint plantID = addPlantInstance(base_position, 0);
3044
3045 AxisRotation base_rotation = make_AxisRotation(0, context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
3046 uint uID_stem = addBaseStemShoot(plantID, 1, base_rotation, 0.002, 0.04, 0.01, 0.01, 0, "mainstem");
3047
3048 breakPlantDormancy(plantID);
3049
3050 setPlantPhenologicalThresholds(plantID, 0, 40, 5, 5, 30, 1000, false);
3051
3052 plant_instances.at(plantID).max_age = 365;
3053
3054 return plantID;
3055}
3056
3057void PlantArchitecture::initializeCherryTomatoShoots() {
3058
3059 // ---- Leaf Prototype ---- //
3060
3061 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
3062 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/CherryTomatoLeaf.png";
3063 leaf_prototype.leaf_aspect_ratio = 0.6f;
3064 leaf_prototype.midrib_fold_fraction = 0.1f;
3065 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.3, -0.15f);
3066 leaf_prototype.lateral_curvature = -0.8f;
3067 leaf_prototype.wave_period = 0.35f;
3068 leaf_prototype.wave_amplitude = 0.08f;
3069 leaf_prototype.subdivisions = 7;
3070 leaf_prototype.unique_prototypes = 5;
3071
3072 // ---- Phytomer Parameters ---- //
3073
3074 PhytomerParameters phytomer_parameters(context_ptr->getRandomGenerator());
3075
3076 phytomer_parameters.internode.pitch = 5;
3077 phytomer_parameters.internode.phyllotactic_angle.uniformDistribution(14, 220);
3078 phytomer_parameters.internode.radius_initial = 0.001;
3079 phytomer_parameters.internode.color = make_RGBcolor(0.217, 0.275, 0.0571);
3080 phytomer_parameters.internode.length_segments = 1;
3081 phytomer_parameters.internode.radial_subdivisions = 14;
3082
3083 phytomer_parameters.petiole.petioles_per_internode = 1;
3084 phytomer_parameters.petiole.pitch.uniformDistribution(45, 60);
3085 phytomer_parameters.petiole.radius = 0.002;
3086 phytomer_parameters.petiole.length = 0.25;
3087 phytomer_parameters.petiole.taper = 0.25;
3088 phytomer_parameters.petiole.curvature.uniformDistribution(-250, 0);
3089 phytomer_parameters.petiole.color = make_RGBcolor(0.32, 0.37, 0.12);
3090 phytomer_parameters.petiole.length_segments = 5;
3091
3092 phytomer_parameters.leaf.leaves_per_petiole = 9;
3093 phytomer_parameters.leaf.pitch.uniformDistribution(-30, 5);
3094 phytomer_parameters.leaf.yaw = 10;
3095 phytomer_parameters.leaf.roll.uniformDistribution(-20, 20);
3096 phytomer_parameters.leaf.leaflet_offset = 0.22;
3097 phytomer_parameters.leaf.leaflet_scale = 0.9;
3098 phytomer_parameters.leaf.prototype_scale.uniformDistribution(0.12, 0.17);
3099 phytomer_parameters.leaf.prototype = leaf_prototype;
3100
3101 phytomer_parameters.peduncle.length = 0.2;
3102 phytomer_parameters.peduncle.radius = 0.0015;
3103 phytomer_parameters.peduncle.pitch = 20;
3104 phytomer_parameters.peduncle.roll = 0;
3105 phytomer_parameters.peduncle.curvature = -1000;
3106 phytomer_parameters.peduncle.color = phytomer_parameters.internode.color;
3107 phytomer_parameters.peduncle.length_segments = 5;
3108 phytomer_parameters.peduncle.radial_subdivisions = 8;
3109
3110 phytomer_parameters.inflorescence.flowers_per_peduncle = 6;
3111 phytomer_parameters.inflorescence.flower_offset = 0.15;
3112 phytomer_parameters.inflorescence.pitch = 80;
3113 phytomer_parameters.inflorescence.roll.uniformDistribution(-10, 10);
3114 phytomer_parameters.inflorescence.flower_prototype_scale = 0.03;
3115 phytomer_parameters.inflorescence.flower_prototype_function = TomatoFlowerPrototype;
3116 phytomer_parameters.inflorescence.fruit_prototype_scale = 0.09;
3117 phytomer_parameters.inflorescence.fruit_prototype_function = TomatoFruitPrototype;
3118 phytomer_parameters.inflorescence.fruit_gravity_factor_fraction = 0.2;
3119
3120 // ---- Shoot Parameters ---- //
3121
3122 ShootParameters shoot_parameters(context_ptr->getRandomGenerator());
3123 shoot_parameters.phytomer_parameters = phytomer_parameters;
3124 shoot_parameters.phytomer_parameters.phytomer_creation_function = CherryTomatoPhytomerCreationFunction;
3125 shoot_parameters.phytomer_parameters.phytomer_callback_function = CherryTomatoPhytomerCallbackFunction;
3126
3127 shoot_parameters.max_nodes = 100;
3128 shoot_parameters.insertion_angle_tip = 30;
3129 shoot_parameters.insertion_angle_decay_rate = 0;
3130 shoot_parameters.internode_length_max = 0.04;
3131 shoot_parameters.internode_length_min = 0.0;
3132 shoot_parameters.internode_length_decay_rate = 0;
3133 shoot_parameters.base_roll = 90;
3134 shoot_parameters.base_yaw.uniformDistribution(-20, 20);
3135 shoot_parameters.gravitropic_curvature = 800;
3136 shoot_parameters.tortuosity = 1.5;
3137
3138 shoot_parameters.phyllochron_min = 4;
3139 shoot_parameters.elongation_rate_max = 0.1;
3140 shoot_parameters.girth_area_factor = 2.f;
3141 shoot_parameters.vegetative_bud_break_time = 40;
3142 shoot_parameters.vegetative_bud_break_probability_min = 0.2;
3143 shoot_parameters.vegetative_bud_break_probability_decay_rate = 0.;
3144 shoot_parameters.flower_bud_break_probability = 0.5;
3145 shoot_parameters.fruit_set_probability = 0.9;
3146 shoot_parameters.flowers_require_dormancy = false;
3147 shoot_parameters.growth_requires_dormancy = false;
3148 shoot_parameters.determinate_shoot_growth = false;
3149
3150 shoot_parameters.defineChildShootTypes({"mainstem"}, {1.0});
3151
3152 defineShootType("mainstem", shoot_parameters);
3153}
3154
3155uint PlantArchitecture::buildCherryTomatoPlant(const helios::vec3 &base_position) {
3156
3157 if (shoot_types.empty()) {
3158 // automatically initialize cherry tomato plant shoots
3159 initializeCherryTomatoShoots();
3160 }
3161
3162 uint plantID = addPlantInstance(base_position, 0);
3163
3164 AxisRotation base_rotation = make_AxisRotation(0, context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI));
3165 uint uID_stem = addBaseStemShoot(plantID, 1, base_rotation, 0.002, 0.06, 0.01, 0.01, 0, "mainstem");
3166
3167 breakPlantDormancy(plantID);
3168
3169 setPlantPhenologicalThresholds(plantID, 0, 50, 10, 5, 30, 1000);
3170
3171 plant_instances.at(plantID).max_age = 175;
3172
3173 return plantID;
3174}
3175
3176void PlantArchitecture::initializeWalnutTreeShoots() {
3177
3178 // ---- Leaf Prototype ---- //
3179
3180 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
3181 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/WalnutLeaf.png";
3182 leaf_prototype.leaf_aspect_ratio = 0.5f;
3183 leaf_prototype.midrib_fold_fraction = 0.15f;
3184 leaf_prototype.longitudinal_curvature = -0.2f;
3185 leaf_prototype.lateral_curvature = 0.1f;
3186 leaf_prototype.wave_period.uniformDistribution(0.08, 0.15);
3187 leaf_prototype.wave_amplitude.uniformDistribution(0.02, 0.04);
3188 leaf_prototype.subdivisions = 3;
3189 leaf_prototype.unique_prototypes = 5;
3190
3191 // ---- Phytomer Parameters ---- //
3192
3193 PhytomerParameters phytomer_parameters_walnut(context_ptr->getRandomGenerator());
3194
3195 phytomer_parameters_walnut.internode.pitch = 0;
3196 phytomer_parameters_walnut.internode.phyllotactic_angle.uniformDistribution(160, 200);
3197 phytomer_parameters_walnut.internode.radius_initial = 0.004;
3198 phytomer_parameters_walnut.internode.length_segments = 1;
3199 phytomer_parameters_walnut.internode.image_texture = "plugins/plantarchitecture/assets/textures/AppleBark.jpg";
3200 phytomer_parameters_walnut.internode.max_floral_buds_per_petiole = 3;
3201
3202 phytomer_parameters_walnut.petiole.petioles_per_internode = 2;
3203 phytomer_parameters_walnut.petiole.pitch.uniformDistribution(-80, -70);
3204 phytomer_parameters_walnut.petiole.taper = 0.2;
3205 phytomer_parameters_walnut.petiole.curvature.uniformDistribution(-1000, 0);
3206 phytomer_parameters_walnut.petiole.length = 0.15;
3207 phytomer_parameters_walnut.petiole.radius = 0.0015;
3208 phytomer_parameters_walnut.petiole.length_segments = 5;
3209 phytomer_parameters_walnut.petiole.radial_subdivisions = 3;
3210 phytomer_parameters_walnut.petiole.color = make_RGBcolor(0.61, 0.5, 0.24);
3211
3212 phytomer_parameters_walnut.leaf.leaves_per_petiole = 5;
3213 phytomer_parameters_walnut.leaf.pitch.uniformDistribution(-40, 0);
3214 phytomer_parameters_walnut.leaf.prototype_scale = 0.14;
3215 phytomer_parameters_walnut.leaf.leaflet_scale = 0.7;
3216 phytomer_parameters_walnut.leaf.leaflet_offset = 0.35;
3217 phytomer_parameters_walnut.leaf.prototype = leaf_prototype;
3218
3219 phytomer_parameters_walnut.peduncle.length = 0.02;
3220 phytomer_parameters_walnut.peduncle.radius = 0.0005;
3221 phytomer_parameters_walnut.peduncle.pitch = 90;
3222 phytomer_parameters_walnut.peduncle.roll = 90;
3223 phytomer_parameters_walnut.peduncle.length_segments = 1;
3224
3225 phytomer_parameters_walnut.inflorescence.flowers_per_peduncle = 1;
3226 phytomer_parameters_walnut.inflorescence.pitch = 0;
3227 phytomer_parameters_walnut.inflorescence.roll = 0;
3228 phytomer_parameters_walnut.inflorescence.flower_prototype_scale = 0.03;
3229 phytomer_parameters_walnut.inflorescence.flower_prototype_function = WalnutFlowerPrototype;
3230 phytomer_parameters_walnut.inflorescence.fruit_prototype_scale = 0.075;
3231 phytomer_parameters_walnut.inflorescence.fruit_prototype_function = WalnutFruitPrototype;
3232
3233 // ---- Shoot Parameters ---- //
3234
3235 // Trunk
3236 ShootParameters shoot_parameters_trunk(context_ptr->getRandomGenerator());
3237 shoot_parameters_trunk.phytomer_parameters = phytomer_parameters_walnut;
3238 shoot_parameters_trunk.phytomer_parameters.internode.phyllotactic_angle = 0;
3239 shoot_parameters_trunk.phytomer_parameters.internode.radius_initial = 0.01;
3240 shoot_parameters_trunk.phytomer_parameters.internode.radial_subdivisions = 24;
3241 shoot_parameters_trunk.max_nodes = 20;
3242 shoot_parameters_trunk.girth_area_factor = 3.f;
3243 shoot_parameters_trunk.vegetative_bud_break_probability_min = 0;
3244 shoot_parameters_trunk.vegetative_bud_break_time = 0;
3245 shoot_parameters_trunk.tortuosity = 1;
3246 shoot_parameters_trunk.internode_length_max = 0.05;
3247 shoot_parameters_trunk.internode_length_decay_rate = 0;
3248 shoot_parameters_trunk.defineChildShootTypes({"scaffold"}, {1});
3249
3250 // Proleptic shoots
3251 ShootParameters shoot_parameters_proleptic(context_ptr->getRandomGenerator());
3252 shoot_parameters_proleptic.phytomer_parameters = phytomer_parameters_walnut;
3253 shoot_parameters_proleptic.phytomer_parameters.internode.color = make_RGBcolor(0.3, 0.2, 0.2);
3254 shoot_parameters_proleptic.phytomer_parameters.phytomer_creation_function = WalnutPhytomerCreationFunction;
3255 // shoot_parameters_proleptic.phytomer_parameters.phytomer_callback_function = WalnutPhytomerCallbackFunction;
3256 shoot_parameters_proleptic.max_nodes = 24;
3257 shoot_parameters_proleptic.max_nodes_per_season = 12;
3258 shoot_parameters_proleptic.phyllochron_min = 2.;
3259 shoot_parameters_proleptic.elongation_rate_max = 0.15;
3260 shoot_parameters_proleptic.girth_area_factor = 8.f;
3261 shoot_parameters_proleptic.vegetative_bud_break_probability_min = 0.025;
3262 shoot_parameters_proleptic.vegetative_bud_break_probability_decay_rate = 0.9;
3263 shoot_parameters_proleptic.vegetative_bud_break_time = 3;
3264 shoot_parameters_proleptic.gravitropic_curvature = 200;
3265 shoot_parameters_proleptic.tortuosity = 5;
3266 shoot_parameters_proleptic.insertion_angle_tip.uniformDistribution(20, 25);
3267 shoot_parameters_proleptic.insertion_angle_decay_rate = 15;
3268 shoot_parameters_proleptic.internode_length_max = 0.08;
3269 shoot_parameters_proleptic.internode_length_min = 0.01;
3270 shoot_parameters_proleptic.internode_length_decay_rate = 0.006;
3271 shoot_parameters_proleptic.fruit_set_probability = 0.3;
3272 shoot_parameters_proleptic.flower_bud_break_probability = 0.3;
3273 shoot_parameters_proleptic.max_terminal_floral_buds = 4;
3274 shoot_parameters_proleptic.flowers_require_dormancy = true;
3275 shoot_parameters_proleptic.growth_requires_dormancy = true;
3276 shoot_parameters_proleptic.determinate_shoot_growth = false;
3277 shoot_parameters_proleptic.defineChildShootTypes({"proleptic"}, {1.0});
3278
3279 // Main scaffolds
3280 ShootParameters shoot_parameters_scaffold = shoot_parameters_proleptic;
3281 shoot_parameters_scaffold.phytomer_parameters.internode.radial_subdivisions = 10;
3282 shoot_parameters_scaffold.max_nodes = 30;
3283 shoot_parameters_scaffold.gravitropic_curvature = 300;
3284 shoot_parameters_scaffold.internode_length_max = 0.06;
3285 shoot_parameters_scaffold.tortuosity = 4;
3286 shoot_parameters_scaffold.defineChildShootTypes({"proleptic"}, {1.0});
3287
3288 defineShootType("trunk", shoot_parameters_trunk);
3289 defineShootType("scaffold", shoot_parameters_scaffold);
3290 defineShootType("proleptic", shoot_parameters_proleptic);
3291}
3292
3293uint PlantArchitecture::buildWalnutTree(const helios::vec3 &base_position) {
3294
3295 if (shoot_types.empty()) {
3296 // automatically initialize walnut tree shoots
3297 initializeWalnutTreeShoots();
3298 }
3299
3300 uint plantID = addPlantInstance(base_position, 0);
3301
3302 uint uID_trunk = addBaseStemShoot(plantID, 19, make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), 0.f * M_PI), shoot_types.at("trunk").phytomer_parameters.internode.radius_initial.val(), 0.04, 1.f, 1.f,
3303 0, "trunk");
3304 appendPhytomerToShoot(plantID, uID_trunk, shoot_types.at("trunk").phytomer_parameters, 0, 0.01, 1, 1);
3305
3306 plant_instances.at(plantID).shoot_tree.at(uID_trunk)->meristem_is_alive = false;
3307
3308 auto phytomers = plant_instances.at(plantID).shoot_tree.at(uID_trunk)->phytomers;
3309 for (const auto &phytomer: phytomers) {
3310 phytomer->removeLeaf();
3311 phytomer->setVegetativeBudState(BUD_DEAD);
3312 phytomer->setFloralBudState(BUD_DEAD);
3313 }
3314
3315 uint Nscaffolds = 4; // context_ptr->randu(4,5);
3316
3317 for (int i = 0; i < Nscaffolds; i++) {
3318 // float pitch = context_ptr->randu(deg2rad(25), deg2rad(35))+i*deg2rad(7.f);
3319 float pitch = context_ptr->randu(deg2rad(45), deg2rad(55));
3320 uint uID_shoot = addChildShoot(plantID, uID_trunk, getShootNodeCount(plantID, uID_trunk) - i - 1, context_ptr->randu(7, 9), make_AxisRotation(pitch, (float(i) + context_ptr->randu(-0.2f, 0.2f)) / float(Nscaffolds) * 2 * M_PI, 0), 0.007, 0.06,
3321 1.f, 1.f, 0.5, "scaffold", 0);
3322 }
3323
3324 makePlantDormant(plantID);
3325
3326 setPlantPhenologicalThresholds(plantID, 165, -1, 3, 7, 20, 200, false);
3327
3328 plant_instances.at(plantID).max_age = 1095;
3329
3330 return plantID;
3331}
3332
3333void PlantArchitecture::initializeWheatShoots() {
3334
3335 // ---- Leaf Prototype ---- //
3336
3337 LeafPrototype leaf_prototype(context_ptr->getRandomGenerator());
3338 leaf_prototype.leaf_texture_file[0] = "plugins/plantarchitecture/assets/textures/SorghumLeaf.png";
3339 leaf_prototype.leaf_aspect_ratio = 0.1f;
3340 leaf_prototype.midrib_fold_fraction = 0.3f;
3341 leaf_prototype.longitudinal_curvature.uniformDistribution(-0.5, -0.1);
3342 leaf_prototype.lateral_curvature = -0.3;
3343 leaf_prototype.petiole_roll = 0.04f;
3344 leaf_prototype.wave_period = 0.1f;
3345 leaf_prototype.wave_amplitude = 0.1f;
3346 leaf_prototype.leaf_buckle_length.uniformDistribution(0.5, 0.6);
3347 leaf_prototype.leaf_buckle_angle.uniformDistribution(25, 35);
3348 leaf_prototype.subdivisions = 20;
3349 leaf_prototype.unique_prototypes = 10;
3350
3351 // ---- Phytomer Parameters ---- //
3352
3353 PhytomerParameters phytomer_parameters_wheat(context_ptr->getRandomGenerator());
3354
3355 phytomer_parameters_wheat.internode.pitch = 0;
3356 phytomer_parameters_wheat.internode.phyllotactic_angle.uniformDistribution(67, 77);
3357 phytomer_parameters_wheat.internode.radius_initial = 0.001;
3358 phytomer_parameters_wheat.internode.color = make_RGBcolor(0.27, 0.31, 0.16);
3359 phytomer_parameters_wheat.internode.length_segments = 1;
3360 phytomer_parameters_wheat.internode.radial_subdivisions = 6;
3361 phytomer_parameters_wheat.internode.max_floral_buds_per_petiole = 0;
3362 phytomer_parameters_wheat.internode.max_vegetative_buds_per_petiole = 0;
3363
3364 phytomer_parameters_wheat.petiole.petioles_per_internode = 1;
3365 phytomer_parameters_wheat.petiole.pitch.uniformDistribution(-40, -20);
3366 phytomer_parameters_wheat.petiole.radius = 0.0;
3367 phytomer_parameters_wheat.petiole.length = 0.005;
3368 phytomer_parameters_wheat.petiole.taper = 0;
3369 phytomer_parameters_wheat.petiole.curvature = 0;
3370 phytomer_parameters_wheat.petiole.length_segments = 1;
3371
3372 phytomer_parameters_wheat.leaf.leaves_per_petiole = 1;
3373 phytomer_parameters_wheat.leaf.pitch = 0;
3374 phytomer_parameters_wheat.leaf.yaw = 0;
3375 phytomer_parameters_wheat.leaf.roll = 0;
3376 phytomer_parameters_wheat.leaf.prototype_scale = 0.22;
3377 phytomer_parameters_wheat.leaf.prototype = leaf_prototype;
3378
3379 phytomer_parameters_wheat.peduncle.length = 0.1;
3380 phytomer_parameters_wheat.peduncle.radius = 0.002;
3381 phytomer_parameters_wheat.peduncle.color = phytomer_parameters_wheat.internode.color;
3382 phytomer_parameters_wheat.peduncle.curvature = -100;
3383 phytomer_parameters_wheat.peduncle.radial_subdivisions = 6;
3384
3385 phytomer_parameters_wheat.inflorescence.flowers_per_peduncle = 1;
3386 phytomer_parameters_wheat.inflorescence.pitch = 0;
3387 phytomer_parameters_wheat.inflorescence.roll = 0;
3388 phytomer_parameters_wheat.inflorescence.fruit_prototype_scale = 0.1;
3389 phytomer_parameters_wheat.inflorescence.fruit_prototype_function = WheatSpikePrototype;
3390
3391 phytomer_parameters_wheat.phytomer_creation_function = WheatPhytomerCreationFunction;
3392
3393 // ---- Shoot Parameters ---- //
3394
3395 ShootParameters shoot_parameters_mainstem(context_ptr->getRandomGenerator());
3396 shoot_parameters_mainstem.phytomer_parameters = phytomer_parameters_wheat;
3397 shoot_parameters_mainstem.vegetative_bud_break_probability_min = 0;
3398 shoot_parameters_mainstem.flower_bud_break_probability = 1;
3399 shoot_parameters_mainstem.phyllochron_min = 2;
3400 shoot_parameters_mainstem.elongation_rate_max = 0.1;
3401 shoot_parameters_mainstem.girth_area_factor = 6.f;
3402 shoot_parameters_mainstem.gravitropic_curvature.uniformDistribution(-500, -200);
3403 shoot_parameters_mainstem.flowers_require_dormancy = false;
3404 shoot_parameters_mainstem.growth_requires_dormancy = false;
3405 shoot_parameters_mainstem.determinate_shoot_growth = false;
3406 shoot_parameters_mainstem.fruit_set_probability = 1.0;
3407 shoot_parameters_mainstem.defineChildShootTypes({"mainstem"}, {1.0});
3408 shoot_parameters_mainstem.max_nodes = 20;
3409 shoot_parameters_mainstem.max_terminal_floral_buds = 1;
3410
3411 defineShootType("mainstem", shoot_parameters_mainstem);
3412}
3413
3414uint PlantArchitecture::buildWheatPlant(const helios::vec3 &base_position) {
3415
3416 if (shoot_types.empty()) {
3417 // automatically initialize wheat plant shoots
3418 initializeWheatShoots();
3419 }
3420
3421 uint plantID = addPlantInstance(base_position - make_vec3(0, 0, 0.025), 0);
3422
3423 uint uID_stem = addBaseStemShoot(plantID, 1, make_AxisRotation(context_ptr->randu(0.f, 0.05f * M_PI), context_ptr->randu(0.f, 2.f * M_PI), context_ptr->randu(0.f, 2.f * M_PI)), 0.001, 0.025, 0.01, 0.01, 0, "mainstem");
3424
3425 breakPlantDormancy(plantID);
3426
3427 setPlantPhenologicalThresholds(plantID, 0, -1, -1, 4, 10, 1000, false);
3428
3429 plant_instances.at(plantID).max_age = 365;
3430
3431 return plantID;
3432}