1#include "BuildGeometry/BuildGeometry.h"
6void BuildGeometry(
const std::string &xml_input_file,
PlantArchitecture *plant_architecture_ptr,
Context *context_ptr, std::vector<std::vector<uint>> &canopy_UUID_vector, std::vector<std::vector<helios::vec3>> &individual_plant_locations) {
8 std::vector<uint> ground_UUIDs;
9 std::vector<uint> leaf_UUIDs;
10 std::vector<uint> petiolule_UUIDs;
11 std::vector<uint> petiole_UUIDs;
12 std::vector<uint> internode_UUIDs;
13 std::vector<uint> peduncle_UUIDs;
14 std::vector<uint> petal_UUIDs;
15 std::vector<uint> sepal_UUIDs;
16 std::vector<uint> fruit_UUIDs;
18 pugi::xml_document xmldoc;
20 std::string xml_error_string;
21 if (!
open_xml_file(xml_input_file, xmldoc, xml_error_string)) {
25 pugi::xml_node helios = xmldoc.child(
"helios");
30 vec2 domain_extent(10, 10);
31 bool domain_extent_read =
false;
32 node = helios.child(
"domain_extent");
34 std::cout <<
"WARNING: No value given for 'domain_extent'. Using default value of " << domain_extent << std::endl;
37 const char *domain_extent_str = node.child_value();
38 if (!
parse_vec2(domain_extent_str, domain_extent)) {
40 }
else if (domain_extent.x <= 0 || domain_extent.y <= 0) {
43 domain_extent_read =
true;
47 vec3 domain_origin(0, 0, 0);
48 bool domain_origin_read =
false;
49 node = helios.child(
"domain_origin");
51 std::cout <<
"WARNING: No value given for 'domain_origin'. Using default value of " << domain_origin << std::endl;
54 const char *domain_origin_str = node.child_value();
55 if (!
parse_vec3(domain_origin_str, domain_origin)) {
58 domain_origin_read =
true;
62 int2 ground_resolution(1, 1);
63 bool ground_resolution_read =
false;
64 node = helios.child(
"ground_resolution");
66 std::cout <<
"WARNING: No value given for 'ground_resolution'. Using default value of " << ground_resolution << std::endl;
69 const char *ground_resolution_str = node.child_value();
70 if (!
parse_int2(ground_resolution_str, ground_resolution)) {
72 }
else if (ground_resolution.x <= 0 || ground_resolution.y <= 0) {
75 ground_resolution_read =
true;
80 bool ground_color_read =
false;
81 node = helios.child(
"ground_color");
84 const char *ground_color_str = node.child_value();
88 ground_color_read =
true;
92 std::string ground_texture_file;
93 node = helios.child(
"ground_texture_file");
96 const char *ground_texture_file_str = node.child_value();
97 ground_texture_file =
trim_whitespace(std::string(ground_texture_file_str));
99 if (ground_texture_file.empty()) {
104 std::string ground_model_file;
105 node = helios.child(
"ground_model_obj_file");
108 const char *ground_model_file_str = node.child_value();
109 ground_model_file =
trim_whitespace(std::string(ground_model_file_str));
113 if (ground_model_file.empty()) {
115 }
else if (ext !=
".obj" && ext !=
".OBJ") {
117 }
else if (!std::filesystem::exists(ground_model_file)) {
122 if (!ground_model_file.empty()) {
123 if (domain_extent_read) {
124 std::cout <<
"WARNING: Both 'domain_extent' and 'ground_model_obj_file' were defined. The domain extent will not be used because it is determined by the geometry in the ground model file." << std::endl;
125 }
else if (domain_origin_read) {
126 std::cout <<
"WARNING: Both 'domain_origin' and 'ground_model_obj_file' were defined. The domain origin will not be used because it is determined by the geometry in the ground model file." << std::endl;
127 }
else if (ground_resolution_read) {
128 std::cout <<
"WARNING: Both 'ground_resolution' and 'ground_model_obj_file' were defined. The ground resolution will not be used because it is determined by the geometry in the ground model file." << std::endl;
129 }
else if (!ground_texture_file.empty()) {
130 std::cout <<
"WARNING: Both 'ground_texture_file' and 'ground_model_obj_file' were defined. The ground texture file will not be used because all ground geometry comes from the ground model file." << std::endl;
131 }
else if (ground_color_read) {
132 std::cout <<
"WARNING: Both 'ground_color' and 'ground_model_obj_file' were defined. The ground color will not be used because it is determined by the geometry in the ground model file." << std::endl;
134 }
else if (ground_color_read && !ground_texture_file.empty()) {
135 std::cout <<
"WARNING: Both 'ground_color' and 'ground_texture_file' were defined. The ground color will be overridden by the texture image." << std::endl;
139 if (!ground_model_file.empty()) {
140 ground_UUIDs = context_ptr->
loadOBJ(ground_model_file.c_str());
142 }
else if (!ground_texture_file.empty()) {
143 ground_objID = context_ptr->
addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution, ground_texture_file.c_str());
145 }
else if (ground_color_read) {
146 ground_objID = context_ptr->
addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution, ground_color);
149 ground_objID = context_ptr->
addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution);
157 for (pugi::xml_node p = helios.child(
"canopy_block"); p; p = p.next_sibling(
"canopy_block")) {
159 std::string canopy_model_file;
160 node = p.child(
"canopy_model_obj_file");
163 const char *canopy_model_file_str = node.child_value();
164 canopy_model_file =
trim_whitespace(std::string(canopy_model_file_str));
168 if (canopy_model_file.empty()) {
170 }
else if (ext !=
".obj" && ext !=
".OBJ") {
172 }
else if (!std::filesystem::exists(ground_model_file)) {
177 vec3 canopy_origin(0, 0, 0);
178 bool canopy_origin_read =
false;
179 node = p.child(
"canopy_origin");
181 std::cout <<
"WARNING: No value given for 'canopy_origin'. Using default value of " << canopy_origin << std::endl;
184 const char *canopy_origin_str = node.child_value();
185 if (!
parse_vec3(canopy_origin_str, canopy_origin)) {
188 canopy_origin_read =
true;
192 int2 plant_count(1, 1);
193 bool plant_count_read =
false;
194 node = p.child(
"plant_count");
196 std::cout <<
"WARNING: No value given for 'plant_count'. Using default value of " << plant_count << std::endl;
199 const char *plant_count_str = node.child_value();
200 if (!
parse_int2(plant_count_str, plant_count)) {
202 }
else if (plant_count.x < 1 || plant_count.y < 1) {
203 helios_runtime_error(
"ERROR: Value given for 'plant_count' must be greater than or equal to 1.");
205 plant_count_read =
true;
209 vec2 plant_spacing(0.5, 0.5);
210 bool plant_spacing_read =
false;
211 node = p.child(
"plant_spacing");
213 std::cout <<
"WARNING: No value given for 'plant_spacing'. Using default value of " << plant_spacing << std::endl;
216 const char *plant_spacing_str = node.child_value();
217 if (!
parse_vec2(plant_spacing_str, plant_spacing)) {
219 }
else if (plant_spacing.x <= 0 || plant_spacing.y <= 0) {
222 plant_spacing_read =
true;
226 std::string plant_library_name;
227 node = p.child(
"plant_library_name");
230 const char *plant_library_name_str = node.child_value();
231 plant_library_name =
trim_whitespace(std::string(plant_library_name_str));
235 bool plant_age_read =
false;
236 node = p.child(
"plant_age");
238 std::cout <<
"WARNING: No value given for 'plant_age'. Using default value of " << plant_age << std::endl;
241 const char *plant_age_str = node.child_value();
244 }
else if (plant_age < 0) {
247 plant_age_read =
true;
251 float ground_clipping_height = 0;
252 bool ground_clipping_height_read =
false;
253 node = p.child(
"ground_clipping_height");
256 const char *ground_clipping_height_str = node.child_value();
257 if (!
parse_float(ground_clipping_height_str, ground_clipping_height)) {
260 ground_clipping_height_read =
true;
265 if (!canopy_model_file.empty()) {
267 if (plant_count_read) {
268 std::cout <<
"WARNING: Both 'plant_count' and 'ground_model_obj_file' were defined. The plant count value will not be used because it is determined by the geometry in the canopy model file." << std::endl;
269 }
else if (plant_spacing_read) {
270 std::cout <<
"WARNING: Both 'plant_spacing' and 'ground_model_obj_file' were defined. The plant spacing value will not be used because it is determined by the geometry in the canopy model file." << std::endl;
273 std::vector<uint> canopy_UUIDs = context_ptr->
loadOBJ(canopy_model_file.c_str());
275 std::vector<helios::vec3> curr_plant_locations{};
276 individual_plant_locations.push_back(curr_plant_locations);
278 if (canopy_origin_read) {
291 canopy_UUID_vector.push_back(canopy_UUIDs);
295 if (plant_library_name.empty()) {
301 if (ground_clipping_height_read) {
305 std::vector<uint> canopy_UUIDs = plant_architecture_ptr->
buildPlantCanopyFromLibrary(canopy_origin, plant_spacing, plant_count, plant_age);
306 std::vector<helios::vec3> curr_plant_locations = plant_architecture_ptr->
getPlantBasePosition(canopy_UUIDs);
307 individual_plant_locations.push_back(curr_plant_locations);
316 if (petal_UUIDs.empty() && sepal_UUIDs.empty()) {
317 petal_UUIDs = flower_UUIDs;
322 canopy_UUID_vector.push_back(canopy_UUIDs);
330 context_ptr->
cropDomainX(domain_origin.x +
make_vec2(-0.5f * domain_extent.x, 0.5f * domain_extent.x));
331 context_ptr->
cropDomainY(domain_origin.y +
make_vec2(-0.5f * domain_extent.y, 0.5f * domain_extent.y));
334 if (deleted_primitives > 0) {
335 std::cout <<
"WARNING: " << deleted_primitives <<
" primitives were deleted because they were overhanging the ground." << std::endl;
352 context_ptr->
setGlobalData(
"petiolule_UUIDs", petiolule_UUIDs);
354 context_ptr->
setGlobalData(
"internode_UUIDs", internode_UUIDs);
355 context_ptr->
setGlobalData(
"peduncle_UUIDs", peduncle_UUIDs);