1.3.49
 
Loading...
Searching...
No Matches
CanopyGenerator.cpp
Go to the documentation of this file.
1
16#include "CanopyGenerator.h"
17#include "pugixml.hpp"
18
19using namespace helios;
20
22static float nullvalue_f = 99999;
24static int nullvalue_i = 99999;
26static std::string nullvalue_s = "99999";
27
32
34 readParametersFromXML(canopy_node);
35}
36
37void BaseCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
38 // ----- canopy origin ------ //
39 vec3 new_canopy_origin = XMLloadvec3(canopy_node, "canopy_origin");
40 if (new_canopy_origin.x != nullvalue_f && new_canopy_origin.y != nullvalue_f) {
41 canopy_origin = new_canopy_origin;
42 }
43
44 // ----- canopy rotation ------ //
45 float new_canopy_rotation = XMLloadfloat(canopy_node, "canopy_rotation");
46 if (new_canopy_rotation != nullvalue_f) {
47 canopy_rotation = new_canopy_rotation;
48 }
49}
50
52
53 leaf_size = make_vec2(0.1, 0.1);
54
56
57 leaf_color = RGB::green;
58
59 leaf_angle_distribution = "spherical";
60
61 leaf_area_index = 1.f;
62
63 canopy_height = 1.f;
64
66
67 buffer = "z";
68}
69
73
74void HomogeneousCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
76
77 // ----- leaf size ------//
78 vec2 new_leaf_size = XMLloadvec2(canopy_node, "leaf_size");
79 if (new_leaf_size.x != nullvalue_f && new_leaf_size.y != nullvalue_f) {
80 leaf_size = new_leaf_size;
81 }
82
83 // ----- leaf subdivisions ------//
84 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
85 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
86 leaf_subdivisions = new_leaf_subdivisions;
87 }
88
89 // ----- leaf color ------//
90 RGBAcolor new_leaf_color = XMLloadrgba(canopy_node, "leaf_color");
91 if (new_leaf_color.a != 0) {
92 leaf_color = make_RGBcolor(new_leaf_color.r, new_leaf_color.g, new_leaf_color.b);
93 }
94
95 // ----- leaf texture file ------//
96 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
97 if (new_leaf_texture_file != nullvalue_s) {
98 leaf_texture_file = new_leaf_texture_file;
99 }
100
101 // ----- leaf area index ------//
102 float LAI = XMLloadfloat(canopy_node, "leaf_area_index");
103 if (LAI != nullvalue_f) {
104 leaf_area_index = LAI;
105 }
106
107 // ----- canopy height ------//
108 float h = XMLloadfloat(canopy_node, "canopy_height");
109 if (h != nullvalue_f) {
110 canopy_height = h;
111 }
112
113 // ----- canopy extent ------//
114 vec2 new_canopy_extent = XMLloadvec2(canopy_node, "canopy_extent");
115 if (new_canopy_extent.x != nullvalue_f && new_canopy_extent.y != nullvalue_f) {
116 canopy_extent = new_canopy_extent;
117 }
118
119 // ----- buffer ------//
120 std::string new_buffer = XMLloadstring(canopy_node, "buffer");
121 if (new_buffer != nullvalue_s) {
122 buffer = new_buffer;
123 }
124}
125
127 std::cout << "HomogeneousCanopyParameters::buildPlant: Cannot build a single plant of canopy type HomogeneousCanopyParameters" << std::endl;
128}
129
131 canopy_generator.buildCanopy(*this);
132}
133
135
136 leaf_size = make_vec2(0.025, 0.025);
137
139
140 leaf_color = RGB::green;
141
142 leaf_angle_distribution = "spherical";
143
144 leaf_area_density = 1.f;
145
146 crown_radius = make_vec3(0.5f, 0.5f, 0.5f);
147
148 canopy_configuration = "uniform";
149
150 plant_spacing = make_vec2(2.f, 2.f);
151
152 plant_count = make_int2(5, 5);
153}
154
158
159void SphericalCrownsCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
161
162 // ----- leaf size ------//
163 vec2 new_leaf_size = XMLloadvec2(canopy_node, "leaf_size");
164 if (new_leaf_size.x != nullvalue_f && new_leaf_size.y != nullvalue_f) {
165 leaf_size = new_leaf_size;
166 }
167
168 // ----- leaf subdivisions ------//
169 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
170 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
171 leaf_subdivisions = new_leaf_subdivisions;
172 }
173
174 // ----- leaf color ------//
175 RGBAcolor new_leaf_color = XMLloadrgba(canopy_node, "leaf_color");
176 if (new_leaf_color.a != 0) {
177 leaf_color = make_RGBcolor(new_leaf_color.r, new_leaf_color.g, new_leaf_color.b);
178 }
179
180 // ----- leaf texture file ------//
181 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
182 if (new_leaf_texture_file != nullvalue_s) {
183 leaf_texture_file = new_leaf_texture_file;
184 }
185
186 // ----- leaf angle distribution ------//
187 std::string new_leaf_angle_distribution = XMLloadstring(canopy_node, "leaf_angle_distribution");
188 if (new_leaf_angle_distribution != nullvalue_s) {
189 leaf_angle_distribution = new_leaf_angle_distribution;
190 }
191
192 // ----- leaf area density ------//
193 float new_leaf_area_density = XMLloadfloat(canopy_node, "leaf_area_density");
194 if (new_leaf_area_density != nullvalue_f) {
195 leaf_area_density = new_leaf_area_density;
196 }
197
198 // ----- crown radius ------//
199 vec3 new_crown_radius = XMLloadvec3(canopy_node, "crown_radius");
200 if (new_crown_radius.x != nullvalue_f && new_crown_radius.y != nullvalue_f) {
201 crown_radius = new_crown_radius;
202 }
203
204 // ----- canopy configuration ------//
205 std::string new_canopy_configuration = XMLloadstring(canopy_node, "canopy_configuration");
206 if (new_canopy_configuration != nullvalue_s) {
207 canopy_configuration = new_canopy_configuration;
208 }
209
210 // ----- plant spacing ------//
211 vec2 new_plant_spacing = XMLloadvec2(canopy_node, "plant_spacing");
212 if (new_plant_spacing.x != nullvalue_f && new_plant_spacing.y != nullvalue_f) {
213 plant_spacing = new_plant_spacing;
214 }
215
216 // ----- plant count ------//
217 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
218 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
219 plant_count = new_plant_count;
220 }
221}
222
224 std::cout << "SphericalCrownsCanopyParameters::buildPlant: Cannot build a single plant of canopy type SphericalCrownsCanopyParameters" << std::endl;
225}
226
228 canopy_generator.buildCanopy(*this);
229}
230
232
233 leaf_size = make_vec2(0.025, 0.025);
234
236
237 leaf_color = RGB::green;
238
239 leaf_angle_distribution = "spherical";
240
241 leaf_area_density = 1.f;
242
243 crown_radius = 0.5f;
244
245 crown_height = 1.f;
246
247 canopy_configuration = "uniform";
248
249 plant_spacing = make_vec2(2.f, 2.f);
250
251 plant_count = make_int2(5, 5);
252}
253
257
258void ConicalCrownsCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
260
261 // ----- leaf size ------//
262 vec2 new_leaf_size = XMLloadvec2(canopy_node, "leaf_size");
263 if (new_leaf_size.x != nullvalue_f && new_leaf_size.y != nullvalue_f) {
264 leaf_size = new_leaf_size;
265 }
266
267 // ----- leaf subdivisions ------//
268 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
269 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
270 leaf_subdivisions = new_leaf_subdivisions;
271 }
272
273 // ----- leaf color ------//
274 RGBAcolor new_leaf_color = XMLloadrgba(canopy_node, "leaf_color");
275 if (new_leaf_color.a != 0) {
276 leaf_color = make_RGBcolor(new_leaf_color.r, new_leaf_color.g, new_leaf_color.b);
277 }
278
279 // ----- leaf texture file ------//
280 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
281 if (new_leaf_texture_file != nullvalue_s) {
282 leaf_texture_file = new_leaf_texture_file;
283 }
284
285 // ----- leaf angle distribution ------//
286 std::string new_leaf_angle_distribution = XMLloadstring(canopy_node, "leaf_angle_distribution");
287 if (new_leaf_angle_distribution != nullvalue_s) {
288 leaf_angle_distribution = new_leaf_angle_distribution;
289 }
290
291 // ----- leaf area density ------//
292 float new_leaf_area_density = XMLloadfloat(canopy_node, "leaf_area_density");
293 if (new_leaf_area_density != nullvalue_f) {
294 leaf_area_density = new_leaf_area_density;
295 }
296
297 // ----- crown radius ------//
298 float new_crown_radius = XMLloadfloat(canopy_node, "crown_radius");
299 if (new_crown_radius != nullvalue_f) {
300 crown_radius = new_crown_radius;
301 }
302
303 // ----- crown height ------//
304 float new_crown_height = XMLloadfloat(canopy_node, "crown_height");
305 if (new_crown_height != nullvalue_f) {
306 crown_height = new_crown_height;
307 }
308
309 // ----- canopy configuration ------//
310 std::string new_canopy_configuration = XMLloadstring(canopy_node, "canopy_configuration");
311 if (new_canopy_configuration != nullvalue_s) {
312 canopy_configuration = new_canopy_configuration;
313 }
314
315 // ----- plant spacing ------//
316 vec2 new_plant_spacing = XMLloadvec2(canopy_node, "plant_spacing");
317 if (new_plant_spacing.x != nullvalue_f && new_plant_spacing.y != nullvalue_f) {
318 plant_spacing = new_plant_spacing;
319 }
320
321 // ----- plant count ------//
322 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
323 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
324 plant_count = new_plant_count;
325 }
326}
327
329 std::cout << "ConicalCrownsCanopyParameters::buildPlant: Cannot build a single plant of canopy type ConicalCrownsCanopyParameters" << std::endl;
330}
331
333 canopy_generator.buildCanopy(*this);
334}
335
337
338 leaf_texture_file = "plugins/canopygenerator/textures/GrapeLeaf.png";
339
340 wood_texture_file = "plugins/canopygenerator/textures/wood.jpg";
341
342 leaf_width = 0.18;
344
346
348
351
354
358
362
363 grape_color = make_RGBcolor(0.18, 0.2, 0.25);
364
366
369
371
372 plant_count = make_int2(3, 3);
373
375
377
379
382}
383
385 readParametersFromXML(canopy_node);
386}
387
388void BaseGrapeVineParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
390
391 float new_leaf_width = XMLloadfloat(canopy_node, "leaf_width");
392 if (new_leaf_width != nullvalue_f) {
393 leaf_width = new_leaf_width;
394 }
395
396 float new_leaf_width_spread = XMLloadfloat(canopy_node, "leaf_width_spread");
397 if (new_leaf_width_spread != nullvalue_f) {
398 leaf_width_spread = new_leaf_width_spread;
399 }
400
401 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
402 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
403 leaf_subdivisions = new_leaf_subdivisions;
404 }
405
406 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
407 if (new_leaf_texture_file != nullvalue_s) {
408 leaf_texture_file = new_leaf_texture_file;
409 }
410
411 std::string new_wood_texture_file = XMLloadstring(canopy_node, "wood_texture_file");
412 if (new_wood_texture_file != nullvalue_s) {
413 wood_texture_file = new_wood_texture_file;
414 }
415
416 int new_wood_subdivisions = XMLloadint(canopy_node, "wood_subdivisions");
417 if (new_wood_subdivisions != nullvalue_i) {
418 wood_subdivisions = new_wood_subdivisions;
419 }
420
421 int new_wood_subdivisions_spread = XMLloadint(canopy_node, "wood_subdivisions_spread");
422 if (new_wood_subdivisions_spread != nullvalue_i) {
423 wood_subdivisions_spread = new_wood_subdivisions_spread;
424 }
425
426 float h = XMLloadfloat(canopy_node, "trunk_height");
427 if (h != nullvalue_f) {
428 trunk_height = h;
429 }
430
431 float new_trunk_height_spread = XMLloadfloat(canopy_node, "trunk_height_spread");
432 if (new_trunk_height_spread != nullvalue_f) {
433 trunk_height_spread = new_trunk_height_spread;
434 }
435
436 float r = XMLloadfloat(canopy_node, "trunk_radius");
437 if (r != nullvalue_f) {
438 trunk_radius = r;
439 }
440
441 float new_trunk_radius_spread = XMLloadfloat(canopy_node, "trunk_radius_spread");
442 if (new_trunk_radius_spread != nullvalue_f) {
443 trunk_radius_spread = new_trunk_radius_spread;
444 }
445
446 float new_cordon_length = XMLloadfloat(canopy_node, "cordon_length");
447 if (new_cordon_length != nullvalue_f) {
448 cordon_length = new_cordon_length;
449 }
450
451 float new_cordon_length_spread = XMLloadfloat(canopy_node, "cordon_length_spread");
452 if (new_cordon_length_spread != nullvalue_f) {
453 cordon_length_spread = new_cordon_length_spread;
454 }
455
456 float ch = XMLloadfloat(canopy_node, "cordon_height");
457 if (ch != nullvalue_f) {
458 cordon_height = ch;
459 }
460
461 float new_cordon_height_spread = XMLloadfloat(canopy_node, "cordon_height_spread");
462 if (new_cordon_height_spread != nullvalue_f) {
463 cordon_height_spread = new_cordon_height_spread;
464 }
465
466 float cr = XMLloadfloat(canopy_node, "cordon_radius");
467 if (cr != nullvalue_f) {
468 cordon_radius = cr;
469 }
470
471 float new_cordon_radius_spread = XMLloadfloat(canopy_node, "cordon_radius_spread");
472 if (new_cordon_radius_spread != nullvalue_f) {
473 cordon_radius_spread = new_cordon_radius_spread;
474 }
475
476 float sl = XMLloadfloat(canopy_node, "shoot_length");
477 if (sl != nullvalue_f) {
478 shoot_length = sl;
479 }
480
481 float new_shoot_length_spread = XMLloadfloat(canopy_node, "shoot_length_spread");
482 if (new_shoot_length_spread != nullvalue_f) {
483 shoot_length_spread = new_shoot_length_spread;
484 }
485
486 float sr = XMLloadfloat(canopy_node, "shoot_radius");
487 if (sr != nullvalue_f) {
488 shoot_radius = sr;
489 }
490
491 float new_shoot_radius_spread = XMLloadfloat(canopy_node, "shoot_radius_spread");
492 if (new_shoot_radius_spread != nullvalue_f) {
493 shoot_radius_spread = new_shoot_radius_spread;
494 }
495
496 int spc = XMLloadint(canopy_node, "shoots_per_cordon");
497 if (spc != nullvalue_i) {
498 shoots_per_cordon = uint(spc);
499 }
500
501 int new_shoots_per_cordon_spread = XMLloadint(canopy_node, "shoots_per_cordon_spread");
502 if (new_shoots_per_cordon_spread != nullvalue_i) {
503 shoots_per_cordon_spread = uint(new_shoots_per_cordon_spread);
504 }
505
506 float lsf = XMLloadfloat(canopy_node, "leaf_spacing_fraction");
507 if (lsf != nullvalue_f) {
509 }
510
511 float new_leaf_spacing_fraction_spread = XMLloadfloat(canopy_node, "leaf_spacing_fraction_spread");
512 if (new_leaf_spacing_fraction_spread != nullvalue_f) {
513 leaf_spacing_fraction_spread = new_leaf_spacing_fraction_spread;
514 }
515
516 float gr = XMLloadfloat(canopy_node, "grape_radius");
517 if (gr != nullvalue_f) {
518 grape_radius = gr;
519 }
520
521 float new_grape_radius_spread = XMLloadfloat(canopy_node, "grape_radius_spread");
522 if (new_grape_radius_spread != nullvalue_f) {
523 grape_radius_spread = new_grape_radius_spread;
524 }
525
526 float clr = XMLloadfloat(canopy_node, "cluster_radius");
527 if (clr != nullvalue_f) {
528 cluster_radius = clr;
529 }
530
531 float new_cluster_radius_spread = XMLloadfloat(canopy_node, "cluster_radius_spread");
532 if (new_cluster_radius_spread != nullvalue_f) {
533 cluster_radius_spread = new_cluster_radius_spread;
534 }
535
536 float clhm = XMLloadfloat(canopy_node, "cluster_height_max");
537 if (clhm != nullvalue_f) {
538 cluster_height_max = clhm;
539 }
540
541 float new_cluster_height_max_spread = XMLloadfloat(canopy_node, "cluster_height_max_spread");
542 if (new_cluster_height_max_spread != nullvalue_f) {
543 cluster_height_max_spread = new_cluster_height_max_spread;
544 }
545
546 RGBAcolor new_grape_color = XMLloadrgba(canopy_node, "grape_color");
547 if (new_grape_color.a != 0) {
548 grape_color = make_RGBcolor(new_grape_color.r, new_grape_color.g, new_grape_color.b);
549 }
550
551 int new_grape_subdivisions = XMLloadint(canopy_node, "grape_subdivisions");
552 if (new_grape_subdivisions != nullvalue_i) {
553 grape_subdivisions = uint(new_grape_subdivisions);
554 }
555
556 int new_grape_subdivisions_spread = XMLloadint(canopy_node, "grape_subdivisions_spread");
557 if (new_grape_subdivisions_spread != nullvalue_i) {
558 grape_subdivisions_spread = uint(new_grape_subdivisions_spread);
559 }
560
561 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
562 if (new_plant_spacing != nullvalue_f) {
563 plant_spacing = new_plant_spacing;
564 }
565
566 float new_plant_spacing_spread = XMLloadfloat(canopy_node, "plant_spacing_spread");
567 if (new_plant_spacing_spread != nullvalue_f) {
568 plant_spacing_spread = new_plant_spacing_spread;
569 }
570
571 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
572 if (new_row_spacing != nullvalue_f) {
573 row_spacing = new_row_spacing;
574 }
575
576 float new_row_spacing_spread = XMLloadfloat(canopy_node, "row_spacing_spread");
577 if (new_row_spacing_spread != nullvalue_f) {
578 row_spacing_spread = new_row_spacing_spread;
579 }
580
581 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
582 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
583 plant_count = new_plant_count;
584 }
585
586 float new_dead_probability = XMLloadfloat(canopy_node, "dead_probability");
587 if (new_dead_probability != nullvalue_f) {
588 if (new_dead_probability < 0 || new_dead_probability > 1)
589 std::cout << "BaseGrapeVineParameters::readParametersFromXML: dead_probability value must be between 0 and 1" << std::endl;
590 else
591 dead_probability = new_dead_probability;
592 }
593
594 float new_missing_plant_probability = XMLloadfloat(canopy_node, "missing_plant_probability");
595 if (new_missing_plant_probability != nullvalue_f) {
596 if (new_missing_plant_probability < 0 || new_missing_plant_probability > 1)
597 std::cout << "BaseGrapeVineParameters::readParametersFromXML: missing_plant_probability value must be between 0 and 1" << std::endl;
598 else
599 missing_plant_probability = new_missing_plant_probability;
600 }
601
602 float new_canopy_rotation_spread = XMLloadfloat(canopy_node, "canopy_rotation_spread");
603 if (new_canopy_rotation_spread != nullvalue_f) {
604 canopy_rotation_spread = new_canopy_rotation_spread;
605 }
606}
607
609 std::cout << "BaseGrapeVineParameters::buildPlant: Cannot build a single plant of canopy type BaseGrapeVineParameters" << std::endl;
610}
611
613 std::cout << "BaseGrapeVineParameters::buildPlant: Cannot build a canopy of type BaseGrapeVineParameters" << std::endl;
614}
615
617
618 trunk_height = 0.7;
619
620 trunk_radius = 0.05;
621
622 cordon_height = 0.9;
623
624 cordon_radius = 0.02;
625
626 shoot_length = 0.9;
627
628 shoot_radius = 0.005;
629
631
633
634 grape_radius = 0.0075;
635
636 cluster_radius = 0.03;
637
638 cluster_height_max = 0.15;
639
641
642 plant_spacing = 2;
643
645
646 row_spacing = 2;
647}
648
650 readParametersFromXML(canopy_node);
651}
652
653void VSPGrapevineParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
655}
656
658 canopy_generator.grapevineVSP(*this, origin);
659}
660
662 canopy_generator.buildCanopy(*this);
663}
664
666
667 trunk_height = 1.3;
668
669 trunk_radius = 0.05;
670
671 cordon_height = 1.5;
672
673 cordon_radius = 0.02;
674
675 cordon_spacing = 1.f;
677
678 shoot_length = 1.2;
679
680 shoot_radius = 0.0025;
681
683
684 shoot_angle_tip = 0.4 * M_PI;
686
687 shoot_angle_base = 0.;
689
691
692 grape_radius = 0.0075;
693
694 cluster_radius = 0.03;
695
696 cluster_height_max = 0.1;
697
699
700 plant_spacing = 2;
701
703
704 row_spacing = 4;
705}
706
708 readParametersFromXML(canopy_node);
709}
710
711void SplitGrapevineParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
713
714 float cs = XMLloadfloat(canopy_node, "cordon_spacing");
715 if (cs != nullvalue_f) {
716 cordon_spacing = cs;
717 }
718
719 float sat = XMLloadfloat(canopy_node, "shoot_angle_tip");
720 if (sat != nullvalue_f) {
721 shoot_angle_tip = sat;
722 }
723
724 float sab = XMLloadfloat(canopy_node, "shoot_angle_base");
725 if (sab != nullvalue_f) {
726 shoot_angle_base = sab;
727 }
728}
729
731 canopy_generator.grapevineSplit(*this, origin);
732}
733
735 canopy_generator.buildCanopy(*this);
736}
737
739
740 trunk_height = 0.7;
741
742 trunk_radius = 0.05;
743
744 cordon_height = 0.9;
745
746 cordon_radius = 0.04;
747
748 shoot_length = 0.9;
749
750 shoot_radius = 0.0025;
751
753
755
756 grape_radius = 0.0075;
757
758 cluster_radius = 0.03;
759
760 cluster_height_max = 0.1;
761
763
764 plant_spacing = 1.5;
765
767
768 row_spacing = 2;
769}
770
774
778
780 canopy_generator.grapevineUnilateral(*this, origin);
781}
782
784 canopy_generator.buildCanopy(*this);
785}
786
788
789 trunk_height = 0.7;
790
791 trunk_radius = 0.05;
792
793 cordon_height = 0.9;
794
795 cordon_radius = 0.02;
796
797 shoot_length = 0.9;
798
799 shoot_radius = 0.0025;
800
802
804
805 grape_radius = 0.0075;
806
807 cluster_radius = 0.03;
808
809 cluster_height_max = 0.1;
810
812
813 plant_spacing = 2;
814
815 row_spacing = 2;
816}
817
821
822void GobletGrapevineParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
824}
825
827 canopy_generator.grapevineGoblet(*this, origin);
828}
829
831 canopy_generator.buildCanopy(*this);
832}
833
835
836 needle_width = 0.0005;
837
838 needle_length = 0.05;
839
840 needle_color = make_RGBcolor(0.67, 0.9, 0.56);
841
843
844 wood_texture_file = "plugins/canopygenerator/textures/wood.jpg";
845
847
848 trunk_height = 10;
849
850 trunk_radius = 0.15;
851
852 base_height = 2.0;
853
854 crown_radius = 0.65;
855
856 shoot_radius = 0.02;
857
858 level_spacing = 0.35;
859
861
862 shoot_angle = 0.3 * M_PI;
863
864 canopy_configuration = "random";
865
866 plant_spacing = make_vec2(10, 10);
867
868 plant_count = make_int2(3, 3);
869}
870
874
875void WhiteSpruceCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
877
878 float new_needle_width = XMLloadfloat(canopy_node, "needle_width");
879 if (new_needle_width != nullvalue_f) {
880 needle_width = new_needle_width;
881 }
882
883 float new_needle_length = XMLloadfloat(canopy_node, "needle_length");
884 if (new_needle_length != nullvalue_f) {
885 needle_length = new_needle_length;
886 }
887
888 int2 new_needle_subdivisions = XMLloadint2(canopy_node, "needle_subdivisions");
889 if (new_needle_subdivisions.x != nullvalue_i && new_needle_subdivisions.y != nullvalue_i) {
890 needle_subdivisions = new_needle_subdivisions;
891 }
892
893 RGBAcolor new_needle_color = XMLloadrgba(canopy_node, "needle_color");
894 if (new_needle_color.a != 0) {
895 needle_color = make_RGBcolor(new_needle_color.r, new_needle_color.g, new_needle_color.b);
896 }
897
898 std::string new_wood_texture_file = XMLloadstring(canopy_node, "wood_texture_file");
899 if (new_wood_texture_file != nullvalue_s) {
900 wood_texture_file = new_wood_texture_file;
901 }
902
903 int new_wood_subdivisions = XMLloadint(canopy_node, "wood_subdivisions");
904 if (new_wood_subdivisions != nullvalue_i) {
905 wood_subdivisions = new_wood_subdivisions;
906 }
907
908 float new_trunk_height = XMLloadfloat(canopy_node, "trunk_height");
909 if (new_trunk_height != nullvalue_f) {
910 trunk_height = new_trunk_height;
911 }
912
913 float new_trunk_radius = XMLloadfloat(canopy_node, "trunk_radius");
914 if (new_trunk_radius != nullvalue_f) {
915 trunk_radius = new_trunk_radius;
916 }
917
918 float new_crown_radius = XMLloadfloat(canopy_node, "crown_radius");
919 if (new_crown_radius != nullvalue_f) {
920 crown_radius = new_crown_radius;
921 }
922
923 float new_shoot_radius = XMLloadfloat(canopy_node, "shoot_radius");
924 if (new_shoot_radius != nullvalue_f) {
925 shoot_radius = new_shoot_radius;
926 }
927
928 float new_level_spacing = XMLloadfloat(canopy_node, "level_spacing");
929 if (new_level_spacing != nullvalue_f) {
930 level_spacing = new_level_spacing;
931 }
932
933 int new_branches_per_level = XMLloadint(canopy_node, "branches_per_level");
934 if (new_branches_per_level != nullvalue_i) {
935 branches_per_level = new_branches_per_level;
936 }
937
938 float new_shoot_angle = XMLloadfloat(canopy_node, "shoot_angle");
939 if (new_shoot_angle != nullvalue_f) {
940 shoot_angle = new_shoot_angle;
941 }
942
943 std::string new_canopy_configuration = XMLloadstring(canopy_node, "canopy_configuration");
944 if (new_canopy_configuration != nullvalue_s) {
945 canopy_configuration = new_canopy_configuration;
946 }
947
948 vec2 new_plant_spacing = XMLloadvec2(canopy_node, "plant_spacing");
949 if (new_plant_spacing.x != nullvalue_f && new_plant_spacing.y != nullvalue_f) {
950 plant_spacing = new_plant_spacing;
951 }
952
953 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
954 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
955 plant_count = new_plant_count;
956 }
957}
958
960 canopy_generator.whitespruce(*this, origin);
961}
962
964 canopy_generator.buildCanopy(*this);
965}
966
968
969 leaf_length = 0.2;
970
972
973 leaf_texture_file = "plugins/canopygenerator/textures/TomatoLeaf_big.png";
974
975 shoot_color = make_RGBcolor(0.35, 0.45, 0.2);
976
978
979 plant_height = 1.;
980
981 fruit_radius = 0.03;
982
983 fruit_color = make_RGBcolor(0.7, 0.28, 0.2);
984
986
987 plant_spacing = 2;
988
989 row_spacing = 2;
990
991 plant_count = make_int2(3, 3);
992}
993
994TomatoParameters::TomatoParameters(const pugi::xml_node canopy_node) : TomatoParameters() {
995 readParametersFromXML(canopy_node);
996}
997
998void TomatoParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
1000
1001 float new_leaf_length = XMLloadfloat(canopy_node, "leaf_length");
1002 if (new_leaf_length != nullvalue_f) {
1003 leaf_length = new_leaf_length;
1004 }
1005
1006 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
1007 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
1008 leaf_subdivisions = new_leaf_subdivisions;
1009 }
1010
1011 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
1012 if (new_leaf_texture_file != nullvalue_s) {
1013 leaf_texture_file = new_leaf_texture_file;
1014 }
1015
1016 RGBAcolor new_shoot_color = XMLloadrgba(canopy_node, "shoot_color");
1017 if (new_shoot_color.a != 0) {
1018 shoot_color = make_RGBcolor(new_shoot_color.r, new_shoot_color.g, new_shoot_color.b);
1019 }
1020
1021 int new_shoot_subdivisions = XMLloadint(canopy_node, "shoot_subdivisions");
1022 if (new_shoot_subdivisions != nullvalue_i) {
1023 shoot_subdivisions = new_shoot_subdivisions;
1024 }
1025
1026 float h = XMLloadfloat(canopy_node, "plant_height");
1027 if (h != nullvalue_f) {
1028 plant_height = h;
1029 }
1030
1031 float gr = XMLloadfloat(canopy_node, "fruit_radius");
1032 if (gr != nullvalue_f) {
1033 fruit_radius = gr;
1034 }
1035
1036 RGBAcolor new_fruit_color = XMLloadrgba(canopy_node, "fruit_color");
1037 if (new_fruit_color.a != 0) {
1038 fruit_color = make_RGBcolor(new_fruit_color.r, new_fruit_color.g, new_fruit_color.b);
1039 }
1040
1041
1042 int new_fruit_subdivisions = XMLloadint(canopy_node, "fruit_subdivisions");
1043 if (new_fruit_subdivisions != nullvalue_i) {
1044 fruit_subdivisions = uint(new_fruit_subdivisions);
1045 }
1046
1047 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
1048 if (new_plant_spacing != nullvalue_f) {
1049 plant_spacing = new_plant_spacing;
1050 }
1051
1052 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
1053 if (new_row_spacing != nullvalue_f) {
1054 row_spacing = new_row_spacing;
1055 }
1056
1057 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
1058 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
1059 plant_count = new_plant_count;
1060 }
1061}
1062
1064 canopy_generator.tomato(*this, origin);
1065}
1066
1068 canopy_generator.buildCanopy(*this);
1069}
1070
1072
1073 leaf_length = 0.1;
1074
1076
1077 leaf_texture_file = "plugins/canopygenerator/textures/StrawberryLeaf.png";
1078
1079 stem_color = make_RGBcolor(0.35, 0.45, 0.2);
1080
1081 stem_subdivisions = 10;
1082
1083 stems_per_plant = 50;
1084
1085 stem_radius = 0.005;
1086
1087 plant_height = 0.4;
1088
1089 fruit_radius = 0.025;
1090
1091 fruit_texture_file = "plugins/canopygenerator/textures/StrawberryTexture.jpg";
1092
1093 fruit_subdivisions = 12;
1094
1095 clusters_per_stem = 0.6;
1096
1097 plant_spacing = 0.5;
1098
1099 row_spacing = 1.5;
1100
1101 plant_count = make_int2(4, 2);
1102}
1103
1105 readParametersFromXML(canopy_node);
1106}
1107
1108void StrawberryParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
1110
1111 float new_leaf_length = XMLloadfloat(canopy_node, "leaf_length");
1112 if (new_leaf_length != nullvalue_f) {
1113 leaf_length = new_leaf_length;
1114 }
1115
1116 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
1117 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
1118 leaf_subdivisions = new_leaf_subdivisions;
1119 }
1120
1121 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
1122 if (new_leaf_texture_file != nullvalue_s) {
1123 leaf_texture_file = new_leaf_texture_file;
1124 }
1125
1126 int new_stem_subdivisions = XMLloadint(canopy_node, "stem_subdivisions");
1127 if (new_stem_subdivisions != nullvalue_i) {
1128 stem_subdivisions = new_stem_subdivisions;
1129 }
1130
1131 float new_stem_radius = XMLloadfloat(canopy_node, "stem_radius");
1132 if (new_stem_radius != nullvalue_f) {
1133 stem_radius = new_stem_radius;
1134 }
1135
1136 float h = XMLloadfloat(canopy_node, "plant_height");
1137 if (h != nullvalue_f) {
1138 plant_height = h;
1139 }
1140
1141 int r = XMLloadint(canopy_node, "stems_per_plant");
1142 if (r != nullvalue_i) {
1143 stems_per_plant = r;
1144 }
1145
1146 float gr = XMLloadfloat(canopy_node, "fruit_radius");
1147 if (gr != nullvalue_f) {
1148 fruit_radius = gr;
1149 }
1150
1151 float clr = XMLloadfloat(canopy_node, "clusters_per_stem");
1152 if (clr != nullvalue_f) {
1153 clusters_per_stem = clr;
1154 }
1155
1156 int new_fruit_subdivisions = XMLloadint(canopy_node, "fruit_subdivisions");
1157 if (new_fruit_subdivisions != nullvalue_i) {
1158 fruit_subdivisions = uint(new_fruit_subdivisions);
1159 }
1160
1161 std::string new_fruit_texture_file = XMLloadstring(canopy_node, "fruit_texture_file");
1162 if (new_fruit_texture_file != nullvalue_s) {
1163 fruit_texture_file = new_fruit_texture_file;
1164 }
1165
1166 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
1167 if (new_plant_spacing != nullvalue_f) {
1168 plant_spacing = new_plant_spacing;
1169 }
1170
1171 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
1172 if (new_row_spacing != nullvalue_f) {
1173 row_spacing = new_row_spacing;
1174 }
1175
1176 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
1177 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
1178 plant_count = new_plant_count;
1179 }
1180}
1181
1183 canopy_generator.strawberry(*this, origin);
1184}
1185
1187 canopy_generator.buildCanopy(*this);
1188}
1189
1191
1192 leaf_length = 0.15;
1193
1195
1196 leaf_texture_file = "plugins/canopygenerator/textures/WalnutLeaf.png";
1197
1198 wood_texture_file = "plugins/canopygenerator/textures/wood.jpg";
1199
1200 wood_subdivisions = 10;
1201
1202 trunk_radius = 0.15;
1203
1204 trunk_height = 4.f;
1205
1206 branch_length = make_vec3(4, 0.75, 0.75);
1207
1208 fruit_radius = 0.04;
1209
1210 fruit_texture_file = "plugins/canopygenerator/textures/WalnutTexture.png";
1211
1212 fruit_subdivisions = 16;
1213
1214 plant_spacing = 6;
1215
1216 row_spacing = 8;
1217
1218 plant_count = make_int2(4, 2);
1219}
1220
1222 readParametersFromXML(canopy_node);
1223}
1224
1225void WalnutCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
1227
1228 float new_leaf_length = XMLloadfloat(canopy_node, "leaf_length");
1229 if (new_leaf_length != nullvalue_f) {
1230 leaf_length = new_leaf_length;
1231 }
1232
1233 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
1234 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
1235 leaf_subdivisions = new_leaf_subdivisions;
1236 }
1237
1238 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
1239 if (new_leaf_texture_file != nullvalue_s) {
1240 leaf_texture_file = new_leaf_texture_file;
1241 }
1242
1243 int new_wood_subdivisions = XMLloadint(canopy_node, "wood_subdivisions");
1244 if (new_wood_subdivisions != nullvalue_i) {
1245 wood_subdivisions = new_wood_subdivisions;
1246 }
1247
1248
1249 float new_trunk_radius = XMLloadfloat(canopy_node, "trunk_radius");
1250 if (new_trunk_radius != nullvalue_f) {
1251 trunk_radius = new_trunk_radius;
1252 }
1253
1254 float new_trunk_height = XMLloadfloat(canopy_node, "trunk_height");
1255 if (new_trunk_height != nullvalue_f) {
1256 trunk_height = new_trunk_height;
1257 }
1258
1259 vec3 new_branch_length = XMLloadvec3(canopy_node, "branch_length");
1260 if (new_branch_length.x != nullvalue_f && new_branch_length.y != nullvalue_f) {
1261 branch_length = new_branch_length;
1262 }
1263
1264 std::string new_fruit_texture_file = XMLloadstring(canopy_node, "fruit_texture_file");
1265 if (new_fruit_texture_file != nullvalue_s) {
1266 fruit_texture_file = new_fruit_texture_file;
1267 }
1268
1269 int new_fruit_subdivisions = XMLloadint(canopy_node, "fruit_subdivisions");
1270 if (new_fruit_subdivisions != nullvalue_i) {
1271 fruit_subdivisions = uint(new_fruit_subdivisions);
1272 }
1273
1274 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
1275 if (new_plant_spacing != nullvalue_f) {
1276 plant_spacing = new_plant_spacing;
1277 }
1278
1279 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
1280 if (new_row_spacing != nullvalue_f) {
1281 row_spacing = new_row_spacing;
1282 }
1283
1284 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
1285 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
1286 plant_count = new_plant_count;
1287 }
1288}
1289
1291 canopy_generator.walnut(*this, origin);
1292}
1293
1295 canopy_generator.buildCanopy(*this);
1296}
1297
1299 sorghum_stage = 5;
1300
1301 // stage 1
1302 s1_stem_length = 0.04;
1303
1304 s1_stem_radius = 0.003;
1305
1307
1308 s1_leaf_size1 = make_vec2(0.14, 0.012);
1309
1310 s1_leaf_size2 = make_vec2(0.12, 0.012);
1311
1312 s1_leaf_size3 = make_vec2(0.06, 0.008);
1313
1314 s1_leaf1_angle = 50;
1315
1316 s1_leaf2_angle = 50;
1317
1318 s1_leaf3_angle = 50;
1319
1321
1322 s1_leaf_texture_file = "plugins/canopygenerator/textures/s1_Sorghum_leaf.png";
1323
1324
1325 // stage 2
1326 s2_stem_length = 0.2;
1327
1328 s2_stem_radius = 0.003;
1329
1331
1332 s2_leaf_size1 = make_vec2(0.25, 0.02);
1333
1334 s2_leaf_size2 = make_vec2(0.14, 0.02);
1335
1336 s2_leaf_size3 = make_vec2(0.2, 0.015);
1337
1338 s2_leaf_size4 = make_vec2(0.12, 0.012);
1339
1340 s2_leaf_size5 = make_vec2(0.08, 0.01);
1341
1342 s2_leaf1_angle = 25;
1343
1344 s2_leaf2_angle = 50;
1345
1346 s2_leaf3_angle = 15;
1347
1348 s2_leaf4_angle = 25;
1349
1350 s2_leaf5_angle = 10;
1351
1353
1354 s2_leaf_texture_file = "plugins/canopygenerator/textures/s2_Sorghum_leaf.png";
1355
1356 // stage 3
1357 s3_stem_length = 1.2;
1358
1359 s3_stem_radius = 0.01;
1360
1362
1363 s3_leaf_size = make_vec2(0.8, 0.08);
1364
1366
1368
1369 s3_mean_leaf_angle = 45;
1370
1371 s3_leaf_texture_file = "plugins/canopygenerator/textures/s3_Sorghum_leaf.png";
1372
1373 // stage 4
1374 s4_stem_length = 1.6;
1375
1376 s4_stem_radius = 0.01;
1377
1379
1380 s4_panicle_size = make_vec2(0.2, 0.06);
1381
1383
1384 s4_seed_texture_file = "plugins/canopygenerator/textures/s4_Sorghum_seed.png";
1385
1386 s4_leaf_size = make_vec2(0.8, 0.08);
1387
1389
1391
1392 s4_mean_leaf_angle = 40;
1393
1394 s4_leaf_texture_file = "plugins/canopygenerator/textures/s4_Sorghum_leaf.png";
1395
1396 // stage 5
1397 s5_stem_length = 2.5;
1398
1399 s5_stem_radius = 0.01;
1400
1401 s5_stem_bend = 0.15;
1402
1404
1405 s5_panicle_size = make_vec2(0.3, 0.08);
1406
1408
1409 s5_seed_texture_file = "plugins/canopygenerator/textures/s5_Sorghum_seed.png";
1410
1411 s5_leaf_size = make_vec2(0.9, 0.125);
1412
1414
1416
1417 s5_mean_leaf_angle = 20; // std = 10 degrees
1418
1419 s5_leaf_texture_file = "plugins/canopygenerator/textures/s5_Sorghum_leaf.png";
1420
1421 // Canopy
1422 plant_spacing = 0.45;
1423
1424 row_spacing = 0.45;
1425
1426 plant_count = make_int2(10, 10);
1427}
1428
1430 readParametersFromXML(canopy_node);
1431}
1432
1433void SorghumCanopyParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
1435
1436 int new_sorghum_stage = XMLloadint(canopy_node, "sorghum_stage");
1437 if (new_sorghum_stage != nullvalue_i) {
1438 sorghum_stage = new_sorghum_stage;
1439 }
1440
1441 // STAGE 1
1442 float new_s1_stem_length = XMLloadint(canopy_node, "s1_stem_length");
1443 if (new_s1_stem_length != nullvalue_i) {
1444 s1_stem_length = new_s1_stem_length;
1445 }
1446
1447 float new_s1_stem_radius = XMLloadfloat(canopy_node, "s1_stem_radius");
1448 if (new_s1_stem_radius != nullvalue_f) {
1449 s1_stem_radius = new_s1_stem_radius;
1450 }
1451
1452 int new_s1_stem_subdivisions = XMLloadint(canopy_node, "s1_stem_subdivisions");
1453 if (new_s1_stem_subdivisions != nullvalue_f) {
1454 s1_stem_subdivisions = uint(new_s1_stem_subdivisions);
1455 }
1456
1457 vec2 new_s1_leaf_size1 = XMLloadvec2(canopy_node, "s1_leaf_size1");
1458 if (new_s1_leaf_size1.x != nullvalue_f && new_s1_leaf_size1.y != nullvalue_f) {
1459 s1_leaf_size1 = new_s1_leaf_size1;
1460 }
1461
1462 vec2 new_s1_leaf_size2 = XMLloadvec2(canopy_node, "s1_leaf_size2");
1463 if (new_s1_leaf_size2.x != nullvalue_f && new_s1_leaf_size2.y != nullvalue_f) {
1464 s1_leaf_size2 = new_s1_leaf_size2;
1465 }
1466
1467 vec2 new_s1_leaf_size3 = XMLloadvec2(canopy_node, "s1_leaf_size3");
1468 if (new_s1_leaf_size3.x != nullvalue_f && new_s1_leaf_size3.y != nullvalue_f) {
1469 s1_leaf_size3 = new_s1_leaf_size3;
1470 }
1471
1472 float new_s1_leaf1_angle = XMLloadfloat(canopy_node, "s1_leaf1_angle");
1473 if (new_s1_leaf1_angle != nullvalue_f) {
1474 s1_leaf1_angle = new_s1_leaf1_angle;
1475 }
1476
1477 float new_s1_leaf2_angle = XMLloadfloat(canopy_node, "s1_leaf2_angle");
1478 if (new_s1_leaf2_angle != nullvalue_f) {
1479 s1_leaf2_angle = new_s1_leaf2_angle;
1480 }
1481
1482 float new_s1_leaf3_angle = XMLloadfloat(canopy_node, "s1_leaf3_angle");
1483 if (new_s1_leaf3_angle != nullvalue_f) {
1484 s1_leaf3_angle = new_s1_leaf3_angle;
1485 }
1486
1487 int2 new_s1_leaf_subdivisions = XMLloadint2(canopy_node, "s1_leaf_subdivisions");
1488 if (new_s1_leaf_subdivisions.x != nullvalue_i && new_s1_leaf_subdivisions.y != nullvalue_i) {
1489 s1_leaf_subdivisions = new_s1_leaf_subdivisions;
1490 }
1491
1492 std::string new_s1_leaf_texture_file = XMLloadstring(canopy_node, "s1_leaf_texture_file");
1493 if (new_s1_leaf_texture_file.compare(nullvalue_s) != 0) {
1494 s1_leaf_texture_file = new_s1_leaf_texture_file;
1495 }
1496
1497 // STAGE 2
1498 float new_s2_stem_length = XMLloadint(canopy_node, "s2_stem_length");
1499 if (new_s2_stem_length != nullvalue_i) {
1500 s2_stem_length = new_s2_stem_length;
1501 }
1502
1503 float new_s2_stem_radius = XMLloadfloat(canopy_node, "s2_stem_radius");
1504 if (new_s2_stem_radius != nullvalue_f) {
1505 s2_stem_radius = new_s2_stem_radius;
1506 }
1507
1508 int new_s2_stem_subdivisions = XMLloadint(canopy_node, "s2_stem_subdivisions");
1509 if (new_s2_stem_subdivisions != nullvalue_f) {
1510 s2_stem_subdivisions = uint(new_s2_stem_subdivisions);
1511 }
1512
1513 vec2 new_s2_leaf_size1 = XMLloadvec2(canopy_node, "s2_leaf_size1");
1514 if (new_s2_leaf_size1.x != nullvalue_f && new_s2_leaf_size1.y != nullvalue_f) {
1515 s2_leaf_size1 = new_s2_leaf_size1;
1516 }
1517
1518 vec2 new_s2_leaf_size2 = XMLloadvec2(canopy_node, "s2_leaf_size2");
1519 if (new_s2_leaf_size2.x != nullvalue_f && new_s2_leaf_size2.y != nullvalue_f) {
1520 s2_leaf_size2 = new_s2_leaf_size2;
1521 }
1522
1523 vec2 new_s2_leaf_size3 = XMLloadvec2(canopy_node, "s2_leaf_size3");
1524 if (new_s2_leaf_size3.x != nullvalue_f && new_s2_leaf_size3.y != nullvalue_f) {
1525 s2_leaf_size3 = new_s2_leaf_size3;
1526 }
1527
1528 vec2 new_s2_leaf_size4 = XMLloadvec2(canopy_node, "s2_leaf_size4");
1529 if (new_s2_leaf_size4.x != nullvalue_f && new_s2_leaf_size4.y != nullvalue_f) {
1530 s2_leaf_size4 = new_s2_leaf_size4;
1531 }
1532
1533 vec2 new_s2_leaf_size5 = XMLloadvec2(canopy_node, "s2_leaf_size5");
1534 if (new_s2_leaf_size5.x != nullvalue_f && new_s2_leaf_size5.y != nullvalue_f) {
1535 s2_leaf_size5 = new_s2_leaf_size5;
1536 }
1537
1538 float new_s2_leaf1_angle = XMLloadfloat(canopy_node, "s2_leaf1_angle");
1539 if (new_s2_leaf1_angle != nullvalue_f) {
1540 s2_leaf1_angle = new_s2_leaf1_angle;
1541 }
1542
1543 float new_s2_leaf2_angle = XMLloadfloat(canopy_node, "s2_leaf2_angle");
1544 if (new_s2_leaf2_angle != nullvalue_f) {
1545 s2_leaf2_angle = new_s2_leaf2_angle;
1546 }
1547
1548 float new_s2_leaf3_angle = XMLloadfloat(canopy_node, "s2_leaf3_angle");
1549 if (new_s2_leaf3_angle != nullvalue_f) {
1550 s2_leaf3_angle = new_s2_leaf3_angle;
1551 }
1552
1553 float new_s2_leaf4_angle = XMLloadfloat(canopy_node, "s2_leaf4_angle");
1554 if (new_s2_leaf4_angle != nullvalue_f) {
1555 s2_leaf4_angle = new_s2_leaf4_angle;
1556 }
1557
1558 float new_s2_leaf5_angle = XMLloadfloat(canopy_node, "s2_leaf5_angle");
1559 if (new_s2_leaf3_angle != nullvalue_f) {
1560 s2_leaf5_angle = new_s2_leaf5_angle;
1561 }
1562
1563 int2 new_s2_leaf_subdivisions = XMLloadint2(canopy_node, "s2_leaf_subdivisions");
1564 if (new_s2_leaf_subdivisions.x != nullvalue_i && new_s2_leaf_subdivisions.y != nullvalue_i) {
1565 s2_leaf_subdivisions = new_s2_leaf_subdivisions;
1566 }
1567
1568 std::string new_s2_leaf_texture_file = XMLloadstring(canopy_node, "s2_leaf_texture_file");
1569 if (new_s2_leaf_texture_file.compare(nullvalue_s) != 0) {
1570 s2_leaf_texture_file = new_s2_leaf_texture_file;
1571 }
1572
1573 // STAGE 3
1574 float new_s3_stem_length = XMLloadint(canopy_node, "s3_stem_length");
1575 if (new_s3_stem_length != nullvalue_i) {
1576 s3_stem_length = new_s3_stem_length;
1577 }
1578
1579 float new_s3_stem_radius = XMLloadfloat(canopy_node, "s3_stem_radius");
1580 if (new_s3_stem_radius != nullvalue_f) {
1581 s3_stem_radius = new_s3_stem_radius;
1582 }
1583
1584 int new_s3_stem_subdivisions = XMLloadint(canopy_node, "s3_stem_subdivisions");
1585 if (new_s3_stem_subdivisions != nullvalue_f) {
1586 s3_stem_subdivisions = uint(new_s3_stem_subdivisions);
1587 }
1588
1589 vec2 new_s3_leaf_size = XMLloadvec2(canopy_node, "s3_leaf_size");
1590 if (new_s3_leaf_size.x != nullvalue_f && new_s3_leaf_size.y != nullvalue_f) {
1591 s3_leaf_size = new_s3_leaf_size;
1592 }
1593
1594 int2 new_s3_leaf_subdivisions = XMLloadint2(canopy_node, "s3_leaf_subdivisions");
1595 if (new_s3_leaf_subdivisions.x != nullvalue_i && new_s3_leaf_subdivisions.y != nullvalue_i) {
1596 s3_leaf_subdivisions = new_s3_leaf_subdivisions;
1597 }
1598
1599 int new_s3_number_of_leaves = XMLloadint(canopy_node, "s3_number_of_leaves");
1600 if (new_s3_number_of_leaves != nullvalue_i) {
1601 s3_number_of_leaves = new_s3_number_of_leaves;
1602 }
1603
1604 float new_s3_mean_leaf_angle = XMLloadfloat(canopy_node, "s3_mean_leaf_angle");
1605 if (new_s3_mean_leaf_angle != nullvalue_f) {
1606 s3_mean_leaf_angle = new_s3_mean_leaf_angle;
1607 }
1608
1609 std::string new_s3_leaf_texture_file = XMLloadstring(canopy_node, "s3_leaf_texture_file");
1610 if (new_s3_leaf_texture_file.compare(nullvalue_s) != 0) {
1611 s3_leaf_texture_file = new_s3_leaf_texture_file;
1612 }
1613
1614 // STAGE 4
1615 float new_s4_stem_length = XMLloadint(canopy_node, "s4_stem_length");
1616 if (new_s4_stem_length != nullvalue_i) {
1617 s4_stem_length = new_s4_stem_length;
1618 }
1619
1620 float new_s4_stem_radius = XMLloadfloat(canopy_node, "s4_stem_radius");
1621 if (new_s4_stem_radius != nullvalue_f) {
1622 s4_stem_radius = new_s4_stem_radius;
1623 }
1624
1625 int new_s4_stem_subdivisions = XMLloadint(canopy_node, "s4_stem_subdivisions");
1626 if (new_s4_stem_subdivisions != nullvalue_f) {
1627 s4_stem_subdivisions = uint(new_s4_stem_subdivisions);
1628 }
1629
1630 vec2 new_s4_panicle_size = XMLloadvec2(canopy_node, "s4_panicle_size");
1631 if (new_s4_panicle_size.x != nullvalue_f && new_s4_panicle_size.y != nullvalue_f) {
1632 s4_panicle_size = new_s4_panicle_size;
1633 }
1634
1635 int new_s4_panicle_subdivisions = XMLloadint(canopy_node, "s4_panicle_subdivisions");
1636 if (new_s4_panicle_subdivisions != nullvalue_f) {
1637 s4_panicle_subdivisions = uint(new_s4_panicle_subdivisions);
1638 }
1639
1640 std::string new_s4_seed_texture_file = XMLloadstring(canopy_node, "s4_seed_texture_file");
1641 if (new_s4_seed_texture_file.compare(nullvalue_s) != 0) {
1642 s4_seed_texture_file = new_s4_seed_texture_file;
1643 }
1644
1645 vec2 new_s4_leaf_size = XMLloadvec2(canopy_node, "s4_leaf_size");
1646 if (new_s4_leaf_size.x != nullvalue_f && new_s4_leaf_size.y != nullvalue_f) {
1647 s4_leaf_size = new_s4_leaf_size;
1648 }
1649
1650 int2 new_s4_leaf_subdivisions = XMLloadint2(canopy_node, "s4_leaf_subdivisions");
1651 if (new_s4_leaf_subdivisions.x != nullvalue_i && new_s4_leaf_subdivisions.y != nullvalue_i) {
1652 s4_leaf_subdivisions = new_s4_leaf_subdivisions;
1653 }
1654
1655 int new_s4_number_of_leaves = XMLloadint(canopy_node, "s4_number_of_leaves");
1656 if (new_s4_number_of_leaves != nullvalue_i) {
1657 s4_number_of_leaves = new_s4_number_of_leaves;
1658 }
1659
1660 float new_s4_mean_leaf_angle = XMLloadfloat(canopy_node, "s4_mean_leaf_angle");
1661 if (new_s4_mean_leaf_angle != nullvalue_f) {
1662 s4_mean_leaf_angle = new_s4_mean_leaf_angle;
1663 }
1664
1665 std::string new_s4_leaf_texture_file = XMLloadstring(canopy_node, "s4_leaf_texture_file");
1666 if (new_s4_leaf_texture_file.compare(nullvalue_s) != 0) {
1667 s4_leaf_texture_file = new_s4_leaf_texture_file;
1668 }
1669
1670 // STAGE 5
1671 float new_s5_stem_length = XMLloadint(canopy_node, "s5_stem_length");
1672 if (new_s5_stem_length != nullvalue_i) {
1673 s5_stem_length = new_s5_stem_length;
1674 }
1675
1676 float new_s5_stem_radius = XMLloadfloat(canopy_node, "s5_stem_radius");
1677 if (new_s5_stem_radius != nullvalue_f) {
1678 s5_stem_radius = new_s5_stem_radius;
1679 }
1680
1681 float new_s5_stem_bend = XMLloadfloat(canopy_node, "s5_stem_bend");
1682 if (new_s5_stem_bend != nullvalue_f) {
1683 s5_stem_bend = new_s5_stem_bend;
1684 }
1685
1686 int new_s5_stem_subdivisions = XMLloadint(canopy_node, "s5_stem_subdivisions");
1687 if (new_s5_stem_subdivisions != nullvalue_f) {
1688 s5_stem_subdivisions = uint(new_s5_stem_subdivisions);
1689 }
1690
1691 vec2 new_s5_panicle_size = XMLloadvec2(canopy_node, "s5_panicle_size");
1692 if (new_s5_panicle_size.x != nullvalue_f && new_s5_panicle_size.y != nullvalue_f) {
1693 s5_panicle_size = new_s5_panicle_size;
1694 }
1695
1696 int new_s5_panicle_subdivisions = XMLloadint(canopy_node, "s5_panicle_subdivisions");
1697 if (new_s5_panicle_subdivisions != nullvalue_f) {
1698 s5_panicle_subdivisions = uint(new_s5_panicle_subdivisions);
1699 }
1700
1701 std::string new_s5_seed_texture_file = XMLloadstring(canopy_node, "s5_seed_texture_file");
1702 if (new_s5_seed_texture_file.compare(nullvalue_s) != 0) {
1703 s5_seed_texture_file = new_s5_seed_texture_file;
1704 }
1705
1706 vec2 new_s5_leaf_size = XMLloadvec2(canopy_node, "s5_leaf_size");
1707 if (new_s5_leaf_size.x != nullvalue_f && new_s5_leaf_size.y != nullvalue_f) {
1708 s5_leaf_size = new_s5_leaf_size;
1709 }
1710
1711 int2 new_s5_leaf_subdivisions = XMLloadint2(canopy_node, "s5_leaf_subdivisions");
1712 if (new_s5_leaf_subdivisions.x != nullvalue_i && new_s5_leaf_subdivisions.y != nullvalue_i) {
1713 s5_leaf_subdivisions = new_s5_leaf_subdivisions;
1714 }
1715
1716 int new_s5_number_of_leaves = XMLloadint(canopy_node, "s5_number_of_leaves");
1717 if (new_s5_number_of_leaves != nullvalue_i) {
1718 s5_number_of_leaves = new_s5_number_of_leaves;
1719 }
1720
1721 float new_s5_mean_leaf_angle = XMLloadfloat(canopy_node, "s5_mean_leaf_angle");
1722 if (new_s5_mean_leaf_angle != nullvalue_f) {
1723 s5_mean_leaf_angle = new_s5_mean_leaf_angle;
1724 }
1725
1726 std::string new_s5_leaf_texture_file = XMLloadstring(canopy_node, "s5_leaf_texture_file");
1727 if (new_s5_leaf_texture_file.compare(nullvalue_s) != 0) {
1728 s5_leaf_texture_file = new_s5_leaf_texture_file;
1729 }
1730
1731 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
1732 if (new_plant_spacing != nullvalue_f) {
1733 plant_spacing = new_plant_spacing;
1734 }
1735
1736 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
1737 if (new_row_spacing != nullvalue_f) {
1738 row_spacing = new_row_spacing;
1739 }
1740
1741 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
1742 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
1743 plant_count = new_plant_count;
1744 }
1745}
1746
1748 canopy_generator.sorghum(*this, origin);
1749}
1750
1752 canopy_generator.buildCanopy(*this);
1753}
1754
1756
1757 leaf_length = 0.075;
1758
1760
1761 leaf_texture_file = "plugins/canopygenerator/textures/BeanLeaf.png";
1762
1763 shoot_color = make_RGBcolor(0.6471, 0.7333, 0.1176);
1764
1765 shoot_subdivisions = 10;
1766
1767 stem_radius = 0.004;
1768
1769 stem_length = 0.075;
1770
1771 leaflet_length = 0.075;
1772
1773 pod_length = 0; // pods not supported yet
1774
1775 pod_color = make_RGBcolor(0.7, 0.28, 0.2);
1776
1777 pod_subdivisions = 8;
1778
1779 plant_spacing = 0.15;
1780
1781 row_spacing = 0.6;
1782
1783 plant_count = make_int2(3, 3);
1784
1786}
1787
1788BeanParameters::BeanParameters(const pugi::xml_node canopy_node) : BeanParameters() {
1789 readParametersFromXML(canopy_node);
1790}
1791
1792void BeanParameters::readParametersFromXML(const pugi::xml_node canopy_node) {
1794
1795 float new_leaf_length = XMLloadfloat(canopy_node, "leaf_length");
1796 if (new_leaf_length != nullvalue_f) {
1797 leaf_length = new_leaf_length;
1798 }
1799
1800 int2 new_leaf_subdivisions = XMLloadint2(canopy_node, "leaf_subdivisions");
1801 if (new_leaf_subdivisions.x != nullvalue_i && new_leaf_subdivisions.y != nullvalue_i) {
1802 leaf_subdivisions = new_leaf_subdivisions;
1803 }
1804
1805 std::string new_leaf_texture_file = XMLloadstring(canopy_node, "leaf_texture_file");
1806 if (new_leaf_texture_file != nullvalue_s) {
1807 leaf_texture_file = new_leaf_texture_file;
1808 }
1809
1810 int new_shoot_subdivisions = XMLloadint(canopy_node, "shoot_subdivisions");
1811 if (new_shoot_subdivisions != nullvalue_i) {
1812 shoot_subdivisions = new_shoot_subdivisions;
1813 }
1814
1815 float new_stem_radius = XMLloadfloat(canopy_node, "stem_radius");
1816 if (new_stem_radius != nullvalue_f) {
1817 stem_radius = new_stem_radius;
1818 }
1819
1820 RGBAcolor new_shoot_color = XMLloadrgba(canopy_node, "shoot_color");
1821 if (new_shoot_color.a != 0) {
1822 shoot_color = make_RGBcolor(new_shoot_color.r, new_shoot_color.g, new_shoot_color.b);
1823 }
1824
1825 float new_stem_length = XMLloadfloat(canopy_node, "stem_length");
1826 if (new_stem_length != nullvalue_f) {
1827 stem_length = new_stem_length;
1828 }
1829
1830 float new_leaflet_length = XMLloadfloat(canopy_node, "leaflet_length");
1831 if (new_leaflet_length != nullvalue_f) {
1832 leaflet_length = new_leaflet_length;
1833 }
1834
1835 float new_pod_length = XMLloadfloat(canopy_node, "pod_length");
1836 if (new_pod_length != nullvalue_f) {
1837 pod_length = new_pod_length;
1838 }
1839
1840 RGBAcolor new_pod_color = XMLloadrgba(canopy_node, "pod_color");
1841 if (new_pod_color.a != 0) {
1842 pod_color = make_RGBcolor(new_pod_color.r, new_pod_color.g, new_pod_color.b);
1843 }
1844
1845 int new_pod_subdivisions = XMLloadint(canopy_node, "pod_subdivisions");
1846 if (new_pod_subdivisions != nullvalue_i) {
1847 pod_subdivisions = new_pod_subdivisions;
1848 }
1849
1850 float new_plant_spacing = XMLloadfloat(canopy_node, "plant_spacing");
1851 if (new_plant_spacing != nullvalue_f) {
1852 plant_spacing = new_plant_spacing;
1853 }
1854
1855 float new_row_spacing = XMLloadfloat(canopy_node, "row_spacing");
1856 if (new_row_spacing != nullvalue_f) {
1857 row_spacing = new_row_spacing;
1858 }
1859
1860 int2 new_plant_count = XMLloadint2(canopy_node, "plant_count");
1861 if (new_plant_count.x != nullvalue_i && new_plant_count.y != nullvalue_i) {
1862 plant_count = new_plant_count;
1863 }
1864
1865 float new_germination_probability = XMLloadfloat(canopy_node, "germination_probability");
1866 if (new_germination_probability != nullvalue_f) {
1867 germination_probability = new_germination_probability;
1868 }
1869}
1870
1872 canopy_generator.bean(*this, origin);
1873}
1874
1876 canopy_generator.buildCanopy(*this);
1877}
1878
1880
1881 context = m_context;
1882
1883 // seed the random number generator
1884 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
1885 generator.seed(seed);
1886
1887 printmessages = true;
1888
1889 enable_element_labels = false;
1890}
1891
1892template<typename CanopyType, typename... Args>
1894 static_assert(std::is_base_of<BaseCanopyParameters, CanopyType>::value, "CanopyType must inherit from BaseCanopyParameters");
1895 canopy_parameters_list.push_back(std::make_shared<CanopyType>(std::forward<Args>(args)...));
1896}
1897
1898std::vector<std::shared_ptr<BaseCanopyParameters>> CanopyGenerator::getCanopyParametersList() {
1899 std::vector<std::shared_ptr<BaseCanopyParameters>> params_list;
1900 for (const auto &params: canopy_parameters_list) {
1901 params_list.push_back(params);
1902 }
1903 return params_list;
1904}
1905
1906void CanopyGenerator::loadXML(const char *filename, bool build) {
1907
1908 if (printmessages) {
1909 std::cout << "Reading XML file: " << filename << "..." << std::flush;
1910 }
1911
1912 // Check if file exists
1913 std::ifstream f(filename);
1914 if (!f.good()) {
1915 std::cerr << "failed." << std::endl;
1916 throw(std::runtime_error("XML file " + std::string(filename) + " does not exist."));
1917 }
1918
1919 // Using "pugixml" parser. See pugixml.org
1920 pugi::xml_document xmldoc;
1921
1922 // load file
1923 pugi::xml_parse_result result = xmldoc.load_file(filename);
1924
1925 // error checking
1926 if (!result) {
1927 std::cout << "failed." << std::endl;
1928 throw(std::runtime_error("XML file " + std::string(filename) + " parsed with errors, attribute value: [" + xmldoc.child("node").attribute("attr").value() + "]\nError description: " + result.description() + "\n"));
1929 }
1930
1931 pugi::xml_node helios = xmldoc.child("helios");
1932
1933 if (helios.empty()) {
1934 std::cout << "failed." << std::endl;
1935 throw(std::runtime_error("ERROR (loadXML): XML file must have tag '<helios> ... </helios>' bounding all other tags."));
1936 }
1937
1938 // looping over any Canopy Generator blocks specified in XML file
1939 for (pugi::xml_node cgen = helios.child("canopygenerator"); cgen; cgen = cgen.next_sibling("CanopyGenerator")) {
1940
1941 // looping over any canopy types specified
1942
1943 // Homogeneous Canopy
1944 for (pugi::xml_node s = cgen.child("HomogeneousCanopyParameters"); s; s = s.next_sibling("HomogeneousCanopyParameters")) {
1945
1946 HomogeneousCanopyParameters homogeneouscanopyparameters(s);
1947 storeCanopyParameters<HomogeneousCanopyParameters>(homogeneouscanopyparameters);
1948 if (build)
1949 buildCanopy(homogeneouscanopyparameters);
1950 }
1951
1952 // Spherical Canopy
1953 for (pugi::xml_node s = cgen.child("SphericalCrownsCanopyParameters"); s; s = s.next_sibling("SphericalCrownsCanopyParameters")) {
1954
1955 SphericalCrownsCanopyParameters sphericalcrownscanopyparameters(s);
1956 storeCanopyParameters<SphericalCrownsCanopyParameters>(sphericalcrownscanopyparameters);
1957 if (build)
1958 buildCanopy(sphericalcrownscanopyparameters);
1959 }
1960
1961 // Conical Canopy
1962 for (pugi::xml_node s = cgen.child("ConicalCrownsCanopyParameters"); s; s = s.next_sibling("ConicalCrownsCanopyParameters")) {
1963
1964 ConicalCrownsCanopyParameters conicalcrownscanopyparameters(s);
1965 storeCanopyParameters<ConicalCrownsCanopyParameters>(conicalcrownscanopyparameters);
1966 if (build)
1967 buildCanopy(conicalcrownscanopyparameters);
1968 }
1969
1970
1971 // VSP Grapevine Canopy
1972 for (pugi::xml_node s = cgen.child("VSPGrapevineParameters"); s; s = s.next_sibling("VSPGrapevineParameters")) {
1973
1974 VSPGrapevineParameters vspgrapevineparameters(s);
1975 storeCanopyParameters<VSPGrapevineParameters>(vspgrapevineparameters);
1976 if (build)
1977 buildCanopy(vspgrapevineparameters);
1978 }
1979
1980 // Split Grapevine Canopy
1981 for (pugi::xml_node s = cgen.child("SplitGrapevineParameters"); s; s = s.next_sibling("SplitGrapevineParameters")) {
1982
1983 SplitGrapevineParameters splitgrapevineparameters(s);
1984 storeCanopyParameters<SplitGrapevineParameters>(splitgrapevineparameters);
1985 if (build)
1986 buildCanopy(splitgrapevineparameters);
1987 }
1988
1989
1990 // UnilateralGrapevineParameters Canopy
1991 for (pugi::xml_node s = cgen.child("UnilateralGrapevineParameters"); s; s = s.next_sibling("UnilateralGrapevineParameters")) {
1992
1993 UnilateralGrapevineParameters unilateralgrapevineparameters(s);
1994 storeCanopyParameters<UnilateralGrapevineParameters>(unilateralgrapevineparameters);
1995 if (build)
1996 buildCanopy(unilateralgrapevineparameters);
1997 }
1998
1999
2000 // GobletGrapevineParameters Canopy
2001 for (pugi::xml_node s = cgen.child("GobletGrapevineParameters"); s; s = s.next_sibling("GobletGrapevineParameters")) {
2002
2003 GobletGrapevineParameters gobletgrapevineparameters(s);
2004 storeCanopyParameters<GobletGrapevineParameters>(gobletgrapevineparameters);
2005 if (build)
2006 buildCanopy(gobletgrapevineparameters);
2007 }
2008
2009
2010 // WhiteSpruceCanopyParameters Canopy
2011 for (pugi::xml_node s = cgen.child("WhiteSpruceCanopyParameters"); s; s = s.next_sibling("WhiteSpruceCanopyParameters")) {
2012
2013 WhiteSpruceCanopyParameters whitesprucecanopyparameters(s);
2014 storeCanopyParameters<WhiteSpruceCanopyParameters>(whitesprucecanopyparameters);
2015 if (build)
2016 buildCanopy(whitesprucecanopyparameters);
2017 }
2018
2019 // StrawberryParameters Canopy
2020 for (pugi::xml_node s = cgen.child("StrawberryParameters"); s; s = s.next_sibling("StrawberryParameters")) {
2021
2022 StrawberryParameters strawberryparameters(s);
2023 storeCanopyParameters<StrawberryParameters>(strawberryparameters);
2024 if (build)
2025 buildCanopy(strawberryparameters);
2026 }
2027
2028 // TomatoParameters Canopy
2029 for (pugi::xml_node s = cgen.child("TomatoParameters"); s; s = s.next_sibling("TomatoParameters")) {
2030
2031 TomatoParameters tomatoparameters(s);
2032 storeCanopyParameters<TomatoParameters>(tomatoparameters);
2033 if (build)
2034 buildCanopy(tomatoparameters);
2035 }
2036
2037 // WalnutCanopyParameters Canopy
2038 for (pugi::xml_node s = cgen.child("WalnutCanopyParameters"); s; s = s.next_sibling("WalnutCanopyParameters")) {
2039
2040 WalnutCanopyParameters walnutcanopyparameters(s);
2041 storeCanopyParameters<WalnutCanopyParameters>(walnutcanopyparameters);
2042 if (build)
2043 buildCanopy(walnutcanopyparameters);
2044 }
2045
2046 // SorghumCanopyParameters Canopy
2047 for (pugi::xml_node s = cgen.child("SorghumCanopyParameters"); s; s = s.next_sibling("SorghumCanopyParameters")) {
2048
2049 SorghumCanopyParameters sorghumcanopyparameters(s);
2050 storeCanopyParameters<SorghumCanopyParameters>(sorghumcanopyparameters);
2051 if (build)
2052 buildCanopy(sorghumcanopyparameters);
2053 }
2054
2055 // BeanParameters Canopy
2056 for (pugi::xml_node s = cgen.child("BeanParameters"); s; s = s.next_sibling("BeanParameters")) {
2057
2058 BeanParameters beanparameters(s);
2059 storeCanopyParameters<BeanParameters>(beanparameters);
2060 if (build)
2061 buildCanopy(beanparameters);
2062 }
2063
2064 // Ground
2065 for (pugi::xml_node s = cgen.child("Ground"); s; s = s.next_sibling("Ground")) {
2066
2067 vec3 origin = XMLloadvec3(s, "origin");
2068 if (origin.x == nullvalue_f || origin.y == nullvalue_f || origin.z == nullvalue_f) {
2069 origin = make_vec3(0, 0, 0);
2070 if (printmessages) {
2071 std::cout << "WARNING: origin not provided for ground in file " << filename << std::endl;
2072 }
2073 }
2074
2075 vec2 extent = XMLloadvec2(s, "extent");
2076 if (extent.x == nullvalue_f || extent.y == nullvalue_f) {
2077 extent = make_vec2(1, 1);
2078 if (printmessages) {
2079 std::cout << "WARNING: horizontal extent not provided for ground in file " << filename << std::endl;
2080 }
2081 }
2082
2083 int2 texture_subtiles = XMLloadint2(s, "texture_subtiles");
2084 if (texture_subtiles.x == nullvalue_i || texture_subtiles.y == nullvalue_i) {
2085 texture_subtiles = make_int2(1, 1);
2086 }
2087
2088 int2 texture_subpatches = XMLloadint2(s, "texture_subpatches");
2089 if (texture_subpatches.x == nullvalue_i || texture_subpatches.y == nullvalue_i) {
2090 texture_subpatches = make_int2(1, 1);
2091 }
2092
2093 std::string texturefile = XMLloadstring(s, "ground_texture_file");
2094 if (texturefile == nullvalue_s) {
2095 texturefile = "plugins/canopygenerator/textures/dirt.jpg";
2096 if (printmessages) {
2097 std::cout << "WARNING: texture map file not provided for ground in file " << filename << std::endl;
2098 }
2099 }
2100
2101 float rotation = XMLloadfloat(s, "rotation");
2102 if (rotation == nullvalue_f) {
2103 rotation = 0;
2104 }
2105
2106 if (build)
2107 buildGround(origin, extent, texture_subtiles, texture_subpatches, texturefile.c_str(), rotation);
2108 }
2109 }
2110
2111 std::cout << "done." << std::endl;
2112}
2113
2114void CanopyGenerator::buildGround(const vec3 &ground_origin, const vec2 &ground_extent, const int2 &texture_subtiles, const int2 &texture_subpatches, const char *ground_texture_file) {
2115 buildGround(ground_origin, ground_extent, texture_subtiles, texture_subpatches, ground_texture_file, 0.f);
2116}
2117
2118void CanopyGenerator::buildGround(const vec3 &ground_origin, const vec2 &ground_extent, const int2 &texture_subtiles, const int2 &texture_subpatches, const char *ground_texture_file, float ground_rotation) {
2119
2120 if (printmessages) {
2121 std::cout << "Ground geometry..." << std::flush;
2122 }
2123
2124 vec2 dx_tile(ground_extent.x / float(texture_subtiles.x), ground_extent.y / float(texture_subtiles.y));
2125
2126 vec2 dx_subpatch(dx_tile.x / float(texture_subpatches.x), dx_tile.y / float(texture_subpatches.y));
2127
2128 std::vector<uint> UUIDs;
2129 for (int j = 0; j < texture_subtiles.y; j++) {
2130 for (int i = 0; i < texture_subtiles.x; i++) {
2131
2132 vec3 center = ground_origin + make_vec3(-0.5f * ground_extent.x + (float(i) + 0.5f) * dx_tile.x, -0.5f * ground_extent.y + (float(j) + 0.5f) * dx_tile.y, 0);
2133
2134 if (ground_rotation != 0) {
2135 center = rotatePointAboutLine(center, ground_origin, make_vec3(0, 0, 1), ground_rotation);
2136 }
2137
2138 UUIDs = context->addTile(center, dx_tile, make_SphericalCoord(0, -ground_rotation), texture_subpatches, ground_texture_file);
2139
2140 UUID_ground.insert(UUID_ground.begin(), UUIDs.begin(), UUIDs.end());
2141 }
2142 }
2143
2144 if (printmessages) {
2145 std::cout << "done." << std::endl;
2146 std::cout << "Ground consists of " << UUID_ground.size() << " total primitives." << std::endl;
2147 }
2148}
2149
2151 for (const auto &canopy_parameters: canopy_parameters_list) {
2152 canopy_parameters->buildCanopy(*this);
2153 }
2154}
2155
2157
2158 if (printmessages) {
2159 std::cout << "Building homogeneous canopy..." << std::flush;
2160 }
2161
2162 std::uniform_real_distribution<float> unif_distribution;
2163
2164 UUID_leaf.resize(1);
2165
2166 uint ID0;
2167 float solidFractionx = 1.f;
2168 if (params.leaf_texture_file.empty()) {
2169 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_color);
2170 } else {
2171 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_texture_file.c_str());
2172 solidFractionx = context->getObjectArea(ID0) / (params.leaf_size.x * params.leaf_size.y);
2173 }
2174
2175 float leafArea = params.leaf_size.x * params.leaf_size.y * solidFractionx;
2176 int Nleaves = (int) lroundf(params.leaf_area_index * params.canopy_extent.x * params.canopy_extent.y / leafArea);
2177
2178 float Lmax = sqrtf(params.leaf_size.x * params.leaf_size.x + params.leaf_size.y * params.leaf_size.y);
2179
2180 for (int i = 0; i < Nleaves; i++) {
2181
2182 float rx = unif_distribution(generator);
2183 float ry = unif_distribution(generator);
2184 float rz = unif_distribution(generator);
2185
2186 float rp = unif_distribution(generator);
2187
2188 vec3 position;
2189
2190
2191 if (params.buffer == "z") {
2192 position = params.canopy_origin + make_vec3((-0.5f + rx) * params.canopy_extent.x, (-0.5f + ry) * params.canopy_extent.y, 0.5f * Lmax + rz * (params.canopy_height - Lmax));
2193 } else if (params.buffer == "xyz") {
2194 position = params.canopy_origin + make_vec3(0.5f * Lmax + (rx) * (params.canopy_extent.x - Lmax) + -0.5f * params.canopy_extent.x, 0.5f * Lmax + (ry) * (params.canopy_extent.y - Lmax) + -0.5f * params.canopy_extent.y,
2195 0.5f * Lmax + rz * (params.canopy_height - Lmax));
2196 } else {
2197 position = params.canopy_origin + make_vec3((-0.5f + rx) * params.canopy_extent.x, (-0.5f + ry) * params.canopy_extent.y, (rz) * (params.canopy_height));
2198 }
2199
2200 SphericalCoord rotation(1.f, sampleLeafPDF(params.leaf_angle_distribution.c_str()), 2.f * float(M_PI) * rp);
2201
2202 uint ID = context->copyObject(ID0);
2203 context->getObjectPointer(ID)->rotate(-rotation.elevation, "y");
2204 context->getObjectPointer(ID)->rotate(rotation.azimuth, "z");
2205 context->getObjectPointer(ID)->translate(position);
2206
2207 std::vector<uint> UUID = context->getObjectPointer(ID)->getPrimitiveUUIDs();
2208
2209 UUID_leaf.front().push_back(UUID);
2210 }
2211
2212 context->deleteObject(ID0);
2213
2214
2215 if (printmessages) {
2216 std::cout << "done." << std::endl;
2217 std::vector<uint> UUIDs_all = getAllUUIDs(0);
2218 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << UUIDs_all.size() << " total primitives." << std::endl;
2219 }
2220}
2221
2223
2224 if (printmessages) {
2225 std::cout << "Building canopy of spherical crowns..." << std::flush;
2226 }
2227
2228 std::uniform_real_distribution<float> unif_distribution;
2229
2230 vec3 r = params.crown_radius;
2231
2232 std::string cconfig = params.canopy_configuration;
2233 if (cconfig != "uniform" && cconfig != "random") {
2234 std::cout << "WARNING: Unknown canopy configuration parameter for spherical crowns canopy: " << cconfig << ". Using uniformly spaced configuration." << std::endl;
2235 cconfig = "uniform";
2236 }
2237
2238 UUID_leaf.resize(params.plant_count.x * params.plant_count.y);
2239
2240 uint ID0;
2241 float solidFractionx = 1.f;
2242 if (params.leaf_texture_file.empty()) {
2243 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_color);
2244 } else {
2245 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_texture_file.c_str());
2246 solidFractionx = context->getObjectArea(ID0) / (params.leaf_size.x * params.leaf_size.y);
2247 }
2248
2249 float leafArea = params.leaf_size.x * params.leaf_size.y * solidFractionx;
2250 int Nleaves = (int) lroundf(4.f / 3.f * float(M_PI) * r.x * r.y * r.z * params.leaf_area_density / leafArea);
2251
2252 vec2 canopy_extent(params.plant_spacing.x * float(params.plant_count.x), params.plant_spacing.y * float(params.plant_count.y));
2253
2254 uint plant_ID = 0;
2255 uint prim_count = 0;
2256 for (int j = 0; j < params.plant_count.y; j++) {
2257 for (int i = 0; i < params.plant_count.x; i++) {
2258
2259 vec3 center;
2260 if (cconfig == "uniform") {
2261 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing.x, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.plant_spacing.y, r.z);
2262 } else if (cconfig == "random") {
2263 float rx = unif_distribution(generator);
2264 float ry = unif_distribution(generator);
2265 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + float(i) * params.plant_spacing.x + r.x + (params.plant_spacing.x - 2.f * r.x) * rx,
2266 -0.5f * canopy_extent.y + float(j) * params.plant_spacing.y + r.y + (params.plant_spacing.y - 2.f * r.y) * ry, r.z);
2267 }
2268
2269 if (params.canopy_rotation != 0) {
2270 center = rotatePointAboutLine(center, params.canopy_origin, make_vec3(0, 0, 1), params.canopy_rotation);
2271 }
2272
2273 for (int l = 0; l < Nleaves; l++) {
2274
2275 vec3 position(-9999, -9999, -9999);
2276
2277 while (pow(position.x, 2) / pow(params.crown_radius.x, 2) + pow(position.y, 2) / pow(params.crown_radius.y, 2) + pow(position.z, 2) / pow(params.crown_radius.z, 2) > 1.f) {
2278
2279 float u = unif_distribution(generator);
2280 float v = unif_distribution(generator);
2281 float w = unif_distribution(generator);
2282
2283 position = make_vec3((-1 + 2.f * u) * r.x, (-1 + 2.f * v) * r.y, (-1 + 2.f * w) * r.z);
2284 }
2285
2286 float theta = sampleLeafPDF(params.leaf_angle_distribution.c_str());
2287 float phi = 2.f * float(M_PI) * unif_distribution(generator);
2288
2289 uint ID = context->copyObject(ID0);
2290 context->getObjectPointer(ID)->rotate(-theta, "y");
2291 context->getObjectPointer(ID)->rotate(phi, "z");
2292 context->getObjectPointer(ID)->translate(center + position);
2293
2294 std::vector<uint> UUID = context->getObjectPointer(ID)->getPrimitiveUUIDs();
2295
2296 UUID_leaf.at(plant_ID).push_back(UUID);
2297 }
2298
2299 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2300 prim_count += UUIDs_all.size();
2301
2302 plant_ID++;
2303 }
2304 }
2305
2306 context->deleteObject(ID0);
2307
2308 if (printmessages) {
2309 std::cout << "done." << std::endl;
2310 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2311 }
2312}
2313
2315
2316 if (printmessages) {
2317 std::cout << "Building canopy of conical crowns..." << std::flush;
2318 }
2319
2320 std::uniform_real_distribution<float> unif_distribution;
2321
2322 float r = params.crown_radius;
2323 float h = params.crown_height;
2324
2325 std::string cconfig = params.canopy_configuration;
2326 if (cconfig != "uniform" && cconfig != "random") {
2327 std::cout << "WARNING: Unknown canopy configuration parameter for conical crowns canopy: " << cconfig << ". Using uniformly spaced configuration." << std::endl;
2328 cconfig = "uniform";
2329 }
2330
2331 UUID_leaf.resize(params.plant_count.x * params.plant_count.y);
2332
2333 uint ID0;
2334 float solidFractionx = 1.f;
2335 if (params.leaf_texture_file.empty()) {
2336 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_color);
2337 } else {
2338 ID0 = context->addTileObject(make_vec3(0, 0, 0), params.leaf_size, make_SphericalCoord(0, 0), params.leaf_subdivisions, params.leaf_texture_file.c_str());
2339 solidFractionx = context->getObjectArea(ID0) / (params.leaf_size.x * params.leaf_size.y);
2340 }
2341
2342 float leafArea = params.leaf_size.x * params.leaf_size.y * solidFractionx;
2343 int Nleaves = (int) lroundf(1.f / 3.f * float(M_PI) * r * r * h * params.leaf_area_density / leafArea);
2344
2345 vec2 canopy_extent(params.plant_spacing.x * float(params.plant_count.x), params.plant_spacing.y * float(params.plant_count.y));
2346
2347 uint plant_ID = 0;
2348 uint prim_count = 0;
2349 for (int j = 0; j < params.plant_count.y; j++) {
2350 for (int i = 0; i < params.plant_count.x; i++) {
2351
2352 vec3 center;
2353 if (cconfig == "uniform") {
2354 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing.x, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.plant_spacing.y, 0);
2355 } else if (cconfig == "random") {
2356 float rx = unif_distribution(generator);
2357 float ry = unif_distribution(generator);
2358 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + float(i) * params.plant_spacing.x + r + (params.plant_spacing.x - 2.f * r) * rx,
2359 -0.5f * canopy_extent.y + float(j) * params.plant_spacing.y + r + (params.plant_spacing.y - 2.f * r) * ry, 0);
2360 }
2361
2362 if (params.canopy_rotation != 0) {
2363 center = rotatePointAboutLine(center, params.canopy_origin, make_vec3(0, 0, 1), params.canopy_rotation);
2364 }
2365
2366 for (int l = 0; l < Nleaves; l++) {
2367
2368 vec3 position(-9999, -9999, -9999);
2369
2370 while ((powf(position.x, 2) + powf(position.y, 2)) / powf(r / h, 2) > powf(h - position.z, 2)) {
2371
2372 float u = unif_distribution(generator);
2373 float v = unif_distribution(generator);
2374 float w = unif_distribution(generator);
2375
2376 position = make_vec3((-1 + 2.f * u) * r, (-1 + 2.f * v) * r, w * h);
2377 }
2378
2379 float theta = sampleLeafPDF(params.leaf_angle_distribution.c_str());
2380 float phi = 2.f * float(M_PI) * unif_distribution(generator);
2381
2382 uint ID = context->copyObject(ID0);
2383 context->getObjectPointer(ID)->rotate(-theta, "y");
2384 context->getObjectPointer(ID)->rotate(phi, "z");
2385 context->getObjectPointer(ID)->translate(center + position);
2386
2387 std::vector<uint> UUID = context->getObjectPointer(ID)->getPrimitiveUUIDs();
2388
2389 UUID_leaf.at(plant_ID).push_back(UUID);
2390 }
2391
2392 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2393 prim_count += UUIDs_all.size();
2394
2395 plant_ID++;
2396 }
2397 }
2398
2399 context->deleteObject(ID0);
2400
2401 if (printmessages) {
2402 std::cout << "done." << std::endl;
2403 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2404 }
2405}
2406
2408
2409 if (printmessages) {
2410 std::cout << "Building canopy of VSP grapevine..." << std::flush;
2411 }
2412
2413 if (params.cordon_height < params.trunk_height) {
2414 std::cout << "failed." << std::endl;
2415 throw(std::runtime_error("ERROR (CanopyGenerator::buildCanopy)): Cannot build VSP grapevine canopy. Cordon height cannot be less than the trunk height."));
2416 }
2417
2418 std::uniform_real_distribution<float> unif_distribution;
2419
2420 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2421
2422 uint prim_count = 0;
2423 for (int j = 0; j < params.plant_count.y; j++) {
2424 for (int i = 0; i < params.plant_count.x; i++) {
2425
2426 if (params.missing_plant_probability > 0) {
2427 float random_draw = context->randu();
2428 if (random_draw <= params.missing_plant_probability) {
2429 // Don't add the plant
2430 continue;
2431 }
2432 }
2433
2434 float plant_spacing = params.plant_spacing + getVariation(params.plant_spacing_spread, generator);
2435 float row_spacing = params.row_spacing + getVariation(params.row_spacing_spread, generator);
2436 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * row_spacing, 0);
2437
2438 uint plant_ID = grapevineVSP(params, center);
2439
2440 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2441 prim_count += UUIDs_all.size();
2442 }
2443 }
2444
2445
2446 if (printmessages) {
2447 std::cout << "done." << std::endl;
2448 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2449 }
2450}
2451
2453
2454 if (printmessages) {
2455 std::cout << "Building canopy of split trellis grapevine..." << std::flush;
2456 }
2457
2458 std::uniform_real_distribution<float> unif_distribution;
2459
2460 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2461
2462 uint prim_count = 0;
2463 for (int j = 0; j < params.plant_count.y; j++) {
2464 for (int i = 0; i < params.plant_count.x; i++) {
2465
2466 if (params.missing_plant_probability > 0) {
2467 float random_draw = context->randu();
2468 if (random_draw <= params.missing_plant_probability) {
2469 // Don't add the plant
2470 continue;
2471 }
2472 }
2473
2474 float plant_spacing = params.plant_spacing + getVariation(params.plant_spacing_spread, generator);
2475 float row_spacing = params.row_spacing + getVariation(params.row_spacing_spread, generator);
2476 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * row_spacing, 0);
2477
2478 uint plant_ID = grapevineSplit(params, center);
2479
2480 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2481 prim_count += UUIDs_all.size();
2482 }
2483 }
2484
2485
2486 if (printmessages) {
2487 std::cout << "done." << std::endl;
2488 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2489 }
2490}
2491
2493
2494 if (printmessages) {
2495 std::cout << "Building canopy of unilateral trellis grapevine..." << std::flush;
2496 }
2497
2498 std::uniform_real_distribution<float> unif_distribution;
2499
2500 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2501
2502 uint prim_count = 0;
2503 for (int j = 0; j < params.plant_count.y; j++) {
2504 for (int i = 0; i < params.plant_count.x; i++) {
2505
2506 if (params.missing_plant_probability > 0) {
2507 float random_draw = context->randu();
2508 if (random_draw <= params.missing_plant_probability) {
2509 // Don't add the plant
2510 continue;
2511 }
2512 }
2513
2514 float plant_spacing = params.plant_spacing + getVariation(params.plant_spacing_spread, generator);
2515 float row_spacing = params.row_spacing + getVariation(params.row_spacing_spread, generator);
2516 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * row_spacing, 0);
2517
2518 uint plant_ID = grapevineUnilateral(params, center);
2519
2520 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2521 prim_count += UUIDs_all.size();
2522 }
2523 }
2524
2525
2526 if (printmessages) {
2527 std::cout << "done." << std::endl;
2528 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2529 }
2530}
2531
2533
2534 if (printmessages) {
2535 std::cout << "Building canopy of goblet trellis grapevine..." << std::flush;
2536 }
2537
2538 std::uniform_real_distribution<float> unif_distribution;
2539
2540 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2541
2542 uint prim_count = 0;
2543 for (int j = 0; j < params.plant_count.y; j++) {
2544 for (int i = 0; i < params.plant_count.x; i++) {
2545
2546 if (params.missing_plant_probability > 0) {
2547 float random_draw = context->randu();
2548 if (random_draw <= params.missing_plant_probability) {
2549 // Don't add the plant
2550 continue;
2551 }
2552 }
2553
2554 float plant_spacing = params.plant_spacing + getVariation(params.plant_spacing_spread, generator);
2555 float row_spacing = params.row_spacing + getVariation(params.row_spacing_spread, generator);
2556 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * row_spacing, 0);
2557
2558 uint plant_ID = grapevineGoblet(params, center);
2559
2560 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2561 prim_count += UUIDs_all.size();
2562 }
2563 }
2564
2565
2566 if (printmessages) {
2567 std::cout << "done." << std::endl;
2568 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2569 }
2570}
2571
2573
2574 if (printmessages) {
2575 std::cout << "Building canopy of white spruce trees..." << std::flush;
2576 }
2577
2578 std::uniform_real_distribution<float> unif_distribution;
2579
2580 vec2 canopy_extent(params.plant_spacing.x * float(params.plant_count.x), params.plant_spacing.y * float(params.plant_count.y));
2581
2582 std::string cconfig = params.canopy_configuration;
2583 if (cconfig != "uniform" && cconfig != "random") {
2584 std::cout << "WARNING: Unknown canopy configuration parameter for white spruce canopy: " << cconfig << ". Using uniformly spaced configuration." << std::endl;
2585 cconfig = "uniform";
2586 }
2587
2588 float r = params.crown_radius;
2589
2590 uint prim_count = 0;
2591 for (int j = 0; j < params.plant_count.y; j++) {
2592 for (int i = 0; i < params.plant_count.x; i++) {
2593
2594 vec3 center;
2595 if (cconfig != "uniform") {
2596 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing.x, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.plant_spacing.y, 0);
2597 } else if (cconfig != "random") {
2598 float rx = unif_distribution(generator);
2599 float ry = unif_distribution(generator);
2600 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + float(i) * params.plant_spacing.x + r + (params.plant_spacing.x - 2.f * r) * rx,
2601 -0.5f * canopy_extent.y + float(j) * params.plant_spacing.y + r + (params.plant_spacing.y - 2.f * r) * ry, 0);
2602 }
2603
2604 if (params.canopy_rotation != 0) {
2605 center = rotatePointAboutLine(center, params.canopy_origin, make_vec3(0, 0, 1), params.canopy_rotation);
2606 }
2607
2608 uint plant_ID = whitespruce(params, center);
2609
2610 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2611 prim_count += UUIDs_all.size();
2612 }
2613 }
2614
2615 if (printmessages) {
2616 std::cout << "done." << std::endl;
2617 std::cout << "Canopy consists of " << UUID_leaf.size() * UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2618 }
2619}
2620
2622
2623 if (printmessages) {
2624 std::cout << "Building canopy of tomato plants..." << std::flush;
2625 }
2626
2627 std::uniform_real_distribution<float> unif_distribution;
2628
2629 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2630
2631 uint prim_count = 0;
2632 for (int j = 0; j < params.plant_count.y; j++) {
2633 for (int i = 0; i < params.plant_count.x; i++) {
2634
2635 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.row_spacing, 0);
2636
2637 uint plant_ID = tomato(params, center);
2638
2639 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2640 prim_count += UUIDs_all.size();
2641 }
2642 }
2643
2644 if (printmessages) {
2645 std::cout << "done." << std::endl;
2646 // std::cout << "Canopy consists of " << UUID_leaf.size()*UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2647 }
2648}
2649
2651
2652 if (printmessages) {
2653 std::cout << "Building canopy of strawberry plants..." << std::flush;
2654 }
2655
2656 std::uniform_real_distribution<float> unif_distribution;
2657
2658 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2659
2660 uint prim_count = 0;
2661 for (int j = 0; j < params.plant_count.y; j++) {
2662 for (int i = 0; i < params.plant_count.x; i++) {
2663
2664 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.row_spacing, 0);
2665
2666 uint plant_ID = strawberry(params, center);
2667
2668 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2669 prim_count += UUIDs_all.size();
2670 }
2671 }
2672
2673 if (printmessages) {
2674 std::cout << "done." << std::endl;
2675 // std::cout << "Canopy consists of " << UUID_leaf.size()*UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2676 }
2677}
2678
2680
2681 if (printmessages) {
2682 std::cout << "Building canopy of walnut trees..." << std::flush;
2683 }
2684
2685 std::uniform_real_distribution<float> unif_distribution;
2686
2687 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2688
2689 uint prim_count = 0;
2690 for (int j = 0; j < params.plant_count.y; j++) {
2691 for (int i = 0; i < params.plant_count.x; i++) {
2692
2693 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.row_spacing, 0);
2694
2695 uint plant_ID = walnut(params, center);
2696
2697 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2698 prim_count += UUIDs_all.size();
2699 }
2700 }
2701
2702 if (printmessages) {
2703 std::cout << "done." << std::endl;
2704 // std::cout << "Canopy consists of " << UUID_leaf.size()*UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2705 }
2706}
2707
2709
2710 if (printmessages) {
2711 std::cout << "Building canopy of sorghum plants..." << std::flush;
2712 }
2713
2714 std::uniform_real_distribution<float> unif_distribution;
2715
2716 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2717
2718 uint prim_count = 0;
2719 for (int j = 0; j < params.plant_count.y; j++) {
2720 for (int i = 0; i < params.plant_count.x; i++) {
2721
2722 vec3 center = params.canopy_origin + make_vec3(-0.5 * canopy_extent.x + (i + 0.5) * params.plant_spacing, -0.5 * canopy_extent.y + (j + 0.5) * params.row_spacing, 0);
2723
2724 uint plant_ID = sorghum(params, center);
2725
2726 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2727 prim_count += UUIDs_all.size();
2728 }
2729 }
2730
2731 if (printmessages) {
2732 std::cout << "done." << std::endl;
2733 // std::cout << "Canopy consists of " << UUID_leaf.size()*UUID_leaf.front().size() << " leaves and " << prim_count << " total primitives." << std::endl;
2734 }
2735}
2736
2738
2739 if (printmessages) {
2740 std::cout << "Building canopy of bean plants..." << std::flush;
2741 }
2742
2743 std::uniform_real_distribution<float> unif_distribution;
2744
2745 vec2 canopy_extent(params.plant_spacing * float(params.plant_count.x), params.row_spacing * float(params.plant_count.y));
2746
2747 uint plant_ID = 0;
2748 uint prim_count = 0;
2749 for (int j = 0; j < params.plant_count.y; j++) {
2750 for (int i = 0; i < params.plant_count.x; i++) {
2751
2752 if (unif_distribution(generator) > params.germination_probability) {
2753 continue;
2754 }
2755
2756 vec3 center = params.canopy_origin + make_vec3(-0.5f * canopy_extent.x + (float(i) + 0.5f) * params.plant_spacing, -0.5f * canopy_extent.y + (float(j) + 0.5f) * params.row_spacing, 0);
2757
2758 if (params.canopy_rotation != 0) {
2759 center = rotatePointAboutLine(center, params.canopy_origin, make_vec3(0, 0, 1), params.canopy_rotation);
2760 }
2761
2762 bean(params, center);
2763
2764 std::vector<uint> UUIDs_all = getAllUUIDs(plant_ID);
2765 prim_count += UUIDs_all.size();
2766
2767 plant_ID++;
2768 }
2769 }
2770
2771 if (printmessages) {
2772 std::cout << "done." << std::endl;
2773 }
2774}
2775
2776float getVariation(float V, std::minstd_rand0 &generator, bool positive) {
2777
2778 std::uniform_real_distribution<float> unif_distribution;
2779
2780 if (positive) {
2781 return unif_distribution(generator) * V;
2782 } else {
2783 return -V + 2.f * unif_distribution(generator) * V;
2784 }
2785}
2786
2787int getVariation(int V, std::minstd_rand0 &generator, bool positive) {
2788
2789 if (positive) {
2790 std::uniform_int_distribution<> unif_distribution(-V, V);
2791 return unif_distribution(generator);
2792 } else {
2793 std::uniform_int_distribution<> unif_distribution(0, V);
2794 return unif_distribution(generator);
2795 }
2796}
2797
2798uint getVariation(uint V, std::minstd_rand0 &generator) {
2799
2800 std::uniform_int_distribution<> unif_distribution(0, V);
2801
2802 return static_cast<uint>(unif_distribution(generator));
2803}
2804
2805float CanopyGenerator::sampleLeafAngle(const std::vector<float> &leafAngleDist) {
2806
2807 std::vector<float> gL = leafAngleDist;
2808
2809 float dTheta = 0.5f * float(M_PI) / float(gL.size());
2810
2811 // make sure PDF is properly normalized
2812 float norm = 0;
2813 for (float i: gL) {
2814 norm += i * dTheta;
2815 }
2816 for (float &i: gL) {
2817 i /= norm;
2818 }
2819 norm = 0;
2820 for (float i: gL) {
2821 norm += i * dTheta;
2822 }
2823 assert(fabs(norm - 1) < 0.001);
2824
2825 // calculate the leaf angle CDF
2826 std::vector<float> leafAngleCDF;
2827 leafAngleCDF.resize(gL.size());
2828 float tsum = 0;
2829 for (int i = 0; i < gL.size(); i++) {
2830 tsum += gL.at(i) * dTheta;
2831 leafAngleCDF.at(i) = tsum;
2832 }
2833
2834 assert(fabs(tsum - 1.f) < 0.001);
2835
2836 // draw from leaf angle PDF
2837 std::uniform_real_distribution<float> unif_distribution;
2838 float rt = unif_distribution(generator);
2839
2840 float theta = -1;
2841 for (int i = 0; i < gL.size(); i++) {
2842 if (rt < leafAngleCDF.at(i)) {
2843 theta = (float(i) + unif_distribution(generator)) * dTheta;
2844 break;
2845 }
2846 }
2847
2848 assert(theta != -1);
2849
2850 return theta;
2851}
2852
2853void CanopyGenerator::cleanDeletedUUIDs(std::vector<uint> &UUIDs) {
2854 for (int p = UUIDs.size() - 1; p >= 0; p--) {
2855 if (!context->doesPrimitiveExist(UUIDs.at(p))) {
2856 std::swap(UUIDs.at(p), UUIDs.back());
2857 UUIDs.pop_back();
2858 }
2859 }
2860}
2861
2862void CanopyGenerator::cleanDeletedUUIDs(std::vector<std::vector<uint>> &UUIDs) {
2863 for (auto &UUID: UUIDs) {
2864 cleanDeletedUUIDs(UUID);
2865 }
2866}
2867
2868void CanopyGenerator::cleanDeletedUUIDs(std::vector<std::vector<std::vector<uint>>> &UUIDs) {
2869 for (auto &UUID: UUIDs) {
2870 cleanDeletedUUIDs(UUID);
2871 }
2872}
2873
2874std::vector<uint> CanopyGenerator::getTrunkUUIDs(uint PlantID) {
2875 if (PlantID >= UUID_trunk.size()) {
2876 throw(std::runtime_error("ERROR (CanopyGenerator::getTrunkUUIDs): Cannot get UUIDs for plant " + std::to_string(PlantID) + " because only " + std::to_string(UUID_trunk.size()) + " plants have been built."));
2877 }
2878
2879 cleanDeletedUUIDs(UUID_trunk.at(PlantID));
2880
2881 return UUID_trunk.at(PlantID);
2882}
2883
2885 std::vector<uint> UUID_flat = flatten(UUID_trunk);
2886 cleanDeletedUUIDs(UUID_flat);
2887 return UUID_flat;
2888}
2889
2890std::vector<uint> CanopyGenerator::getBranchUUIDs(uint PlantID) {
2891 if (PlantID >= UUID_branch.size()) {
2892 throw(std::runtime_error("ERROR (CanopyGenerator::getBranchUUIDs): Cannot get UUIDs for plant " + std::to_string(PlantID) + " because only " + std::to_string(UUID_branch.size()) + " plants have been built."));
2893 }
2894
2895 cleanDeletedUUIDs(UUID_branch.at(PlantID));
2896
2897 return UUID_branch.at(PlantID);
2898}
2899
2901 std::vector<uint> UUID_flat = flatten(UUID_branch);
2902 cleanDeletedUUIDs(UUID_flat);
2903 return UUID_flat;
2904}
2905
2906std::vector<std::vector<uint>> CanopyGenerator::getLeafUUIDs(uint PlantID) {
2907 if (PlantID >= UUID_leaf.size()) {
2908 throw(std::runtime_error("ERROR (CanopyGenerator::getLeafUUIDs): Cannot get UUIDs for plant " + std::to_string(PlantID) + " because only " + std::to_string(UUID_leaf.size()) + " plants have been built."));
2909 }
2910
2911 cleanDeletedUUIDs(UUID_leaf.at(PlantID));
2912
2913 return UUID_leaf.at(PlantID);
2914}
2915
2917 std::vector<uint> UUID_flat = flatten(UUID_leaf);
2918 cleanDeletedUUIDs(UUID_flat);
2919 return UUID_flat;
2920}
2921
2922std::vector<std::vector<std::vector<uint>>> CanopyGenerator::getFruitUUIDs(uint PlantID) {
2923 if (PlantID >= UUID_fruit.size()) {
2924 throw(std::runtime_error("ERROR (CanopyGenerator::getFruitUUIDs): Cannot get UUIDs for plant " + std::to_string(PlantID) + " because only " + std::to_string(UUID_fruit.size()) + " plants have been built."));
2925 }
2926
2927 cleanDeletedUUIDs(UUID_fruit.at(PlantID));
2928
2929 return UUID_fruit.at(PlantID);
2930}
2931
2933
2934 std::vector<uint> UUIDs_flat, U;
2935
2936 for (auto &p: UUID_fruit) {
2937 U = flatten(p);
2938 UUIDs_flat.insert(UUIDs_flat.end(), U.begin(), U.end());
2939 }
2940
2941 cleanDeletedUUIDs(UUIDs_flat);
2942 return UUIDs_flat;
2943}
2944
2946
2947 std::vector<uint> UUID;
2948
2949 for (uint i: UUID_ground) {
2950
2951 if (context->doesPrimitiveExist(i)) {
2952 UUID.push_back(i);
2953 }
2954 }
2955
2956 return UUID;
2957}
2958
2959std::vector<uint> CanopyGenerator::getAllUUIDs(uint PlantID) {
2960 std::vector<uint> UUIDs;
2961 if (UUID_trunk.size() > PlantID) {
2962 UUIDs.insert(UUIDs.end(), UUID_trunk.at(PlantID).begin(), UUID_trunk.at(PlantID).end());
2963 }
2964 if (UUID_branch.size() > PlantID) {
2965 UUIDs.insert(UUIDs.end(), UUID_branch.at(PlantID).begin(), UUID_branch.at(PlantID).end());
2966 }
2967 if (UUID_leaf.size() > PlantID) {
2968 for (auto &i: UUID_leaf.at(PlantID)) {
2969 UUIDs.insert(UUIDs.end(), i.begin(), i.end());
2970 }
2971 }
2972 if (UUID_fruit.size() > PlantID) {
2973 for (auto &j: UUID_fruit.at(PlantID)) {
2974 for (auto &i: j) {
2975 UUIDs.insert(UUIDs.end(), i.begin(), i.end());
2976 }
2977 }
2978 }
2979
2980 cleanDeletedUUIDs(UUIDs);
2981
2982 return UUIDs;
2983}
2984
2986 return UUID_leaf.size();
2987}
2988
2990 generator.seed(seed);
2991}
2992
2994 printmessages = false;
2995}
2996
2998 printmessages = true;
2999}
3000
3002 for (const auto &params: canopy_parameters_list) {
3003 params->buildPlant(*this, position);
3004 }
3005}
3006
3008 for (const auto &params: canopy_parameters_list) {
3009 vec3 position = params->canopy_origin;
3010 params->buildPlant(*this, position);
3011 }
3012}
3013
3014helios::vec3 interpolateTube(const std::vector<vec3> &P, float frac) {
3015
3016 assert(frac >= 0 && frac <= 1);
3017 assert(!P.empty());
3018
3019 float dl = 0.f;
3020 for (int i = 0; i < P.size() - 1; i++) {
3021 dl += (P.at(i + 1) - P.at(i)).magnitude();
3022 }
3023
3024 float f = 0;
3025 for (int i = 0; i < P.size() - 1; i++) {
3026
3027 float dseg = (P.at(i + 1) - P.at(i)).magnitude();
3028
3029 float fplus = f + dseg / dl;
3030
3031 if (fplus >= 1.f) {
3032 fplus = 1.f + 1e-3;
3033 }
3034
3035 if (frac >= f && (frac <= fplus || fabs(frac - fplus) < 0.0001)) {
3036
3037 vec3 V = P.at(i) + (frac - f) / (fplus - f) * (P.at(i + 1) - P.at(i));
3038
3039 return V;
3040 }
3041
3042 f = fplus;
3043 }
3044
3045 return P.front();
3046}
3047
3048float interpolateTube(const std::vector<float> &P, float frac) {
3049
3050 assert(frac >= 0 && frac <= 1);
3051 assert(!P.empty());
3052
3053 float dl = 0.f;
3054 for (int i = 0; i < P.size() - 1; i++) {
3055 dl += (P.at(i + 1) - P.at(i));
3056 }
3057
3058 float f = 0;
3059 for (int i = 0; i < P.size() - 1; i++) {
3060
3061 float dseg = (P.at(i + 1) - P.at(i));
3062
3063 float fplus = f + dseg / dl;
3064
3065 if (fplus >= 1.f) {
3066 fplus = 1.f + 1e-3;
3067 }
3068
3069 if (frac >= f && (frac <= fplus || fabs(frac - fplus) < 0.0001)) {
3070
3071 float V = P.at(i) + (frac - f) / (fplus - f) * (P.at(i + 1) - P.at(i));
3072
3073 return V;
3074 }
3075
3076 f = fplus;
3077 }
3078
3079 return P.front();
3080}
3081
3082float evaluateCDFresid(float thetaL, std::vector<float> &ru_v, const void *a_distribution) {
3083
3084 assert(!ru_v.empty());
3085 assert(ru_v.front() >= 0.f && ru_v.front() <= 1.f);
3086
3087 float ru = ru_v.front();
3088
3089 const char *distribution = reinterpret_cast<const char *>(a_distribution);
3090
3091 float CDFresid = INFINITY;
3092 if (strcmp(distribution, "planophile") == 0) {
3093 CDFresid = ru - 2.f / float(M_PI) * (thetaL + 0.5f * sinf(2.f * thetaL));
3094 } else if (strcmp(distribution, "erectophile") == 0) {
3095 CDFresid = ru - 2.f / float(M_PI) * (thetaL - 0.5f * sinf(2.f * thetaL));
3096 } else if (strcmp(distribution, "plagiophile") == 0) {
3097 CDFresid = ru - 2.f / float(M_PI) * (thetaL - 0.25f * sinf(4.f * thetaL));
3098 } else if (strcmp(distribution, "extremophile") == 0) {
3099 CDFresid = ru - 2.f / float(M_PI) * (thetaL + 0.25f * sinf(4.f * thetaL));
3100 }
3101
3102 return CDFresid;
3103}
3104
3105float CanopyGenerator::sampleLeafPDF(const char *distribution) {
3106
3107 float thetaL;
3108
3109 std::uniform_real_distribution<float> unif_distribution;
3110
3111 float ru = unif_distribution(generator);
3112
3113 if (strcmp(distribution, "spherical") == 0) {
3114 thetaL = acos_safe(1.f - ru);
3115 } else if (strcmp(distribution, "uniform") == 0) {
3116 thetaL = ru * 0.5f * float(M_PI);
3117 } else if (strcmp(distribution, "planophile") == 0 || strcmp(distribution, "erectophile") == 0 || strcmp(distribution, "plagiophile") == 0 || strcmp(distribution, "extremophile") == 0) {
3118
3119 std::vector<float> args{ru};
3120
3121 thetaL = fzero(evaluateCDFresid, args, distribution, 0.25f);
3122
3123 } else {
3124 throw(std::runtime_error("ERROR (sampleLeafPDF): Invalid leaf angle distribution of " + std::string(distribution) + " specified."));
3125 }
3126
3127 return thetaL;
3128}
3129
3131 enable_element_labels = true;
3132}
3133
3135 enable_element_labels = false;
3136}