1.3.64
 
Loading...
Searching...
No Matches
ProjectBuilder.cpp
1#ifdef _WIN32
2#ifndef NOMINMAX
3#define NOMINMAX
4#endif
5#define WIN32_LEAN_AND_MEAN
6#include <windows.h> //This header must come first!!!
7#include <commdlg.h>
8#include <thread>
9#elif defined(__APPLE__)
10#ifdef ENABLE_HELIOS_VISUALIZER
11#include <nfd.h>
12#endif
13#elif defined(__linux__)
14#ifdef ENABLE_HELIOS_VISUALIZER
15#include <nfd.h>
16#endif
17#include <cstdlib>
18#include <cstring>
19#endif
20
21// OpenGL/ImGui includes - must come after Windows headers but before ProjectBuilder.h
22#ifdef ENABLE_HELIOS_VISUALIZER
23// IMPORTANT: glew.h must be included before any OpenGL headers (including GLFW)
24#include "glew.h"
25// IMGUI
26#define GLFW_INCLUDE_NONE // Prevent GLFW from including OpenGL headers
27#include "GLFW/glfw3.h"
28#include "backends/imgui_impl_glfw.h"
29#include "backends/imgui_impl_opengl3.h"
30#include "imgui.h"
31#include "imgui_internal.h"
32#include "misc/cpp/imgui_stdlib.h"
33#endif // HELIOS_VISUALIZER
34
35#include "ProjectBuilder.h"
36
37
38#ifdef ENABLE_BOUNDARYLAYERCONDUCTANCEMODEL
39const bool enable_blconductance = true;
40#else
41const bool enable_blconductance = false;
42#endif // BOUNDARYLAYERCONDUCTANCEMODEL
43
44#ifdef ENABLE_ENERGYBALANCEMODEL
45const bool enable_energybalance = true;
46#else
47const bool enable_energybalance = false;
48#endif // ENERGYBALANCEMODEL
49
50#ifdef ENABLE_PLANT_ARCHITECTURE
51const bool enable_plantarchitecture = true;
52#else
53const bool enable_plantarchitecture = false;
54#endif // PLANT_ARCHITECTURE
55
56#ifdef ENABLE_RADIATION_MODEL
57const bool enable_radiation = true;
58#else
59const bool enable_radiation = false;
60#endif // RADIATION_MODEL
61
62#ifdef ENABLE_SOLARPOSITION
63const bool enable_solarposition = true;
64#else
65const bool enable_solarposition = false;
66#endif // SOLARPOSITION
67
68#ifdef ENABLE_HELIOS_VISUALIZER
69const bool enable_visualizer = true;
70#else
71const bool enable_visualizer = false;
72#endif // HELIOS_VISUALIZER
73
74
75using namespace helios;
76
77
78std::string vec_to_string(const int2 &v) {
79 std::ostringstream oss;
80 oss << v.x << " " << v.y;
81 return oss.str();
82}
83
84std::string vec_to_string(const vec2 &v) {
85 std::ostringstream oss;
86 oss << v.x << " " << v.y;
87 return oss.str();
88}
89
90std::string vec_to_string(const vec3 &v) {
91 std::ostringstream oss;
92 oss << v.x << " " << v.y << " " << v.z;
93 return oss.str();
94}
95
96std::vector<vec3> interpolate(const std::vector<int> &keypoints, const std::vector<helios::vec3> &positions, int num_points) {
97 std::vector<vec3> pos = positions;
98 std::vector<vec3> result(num_points);
99 std::vector<int> keypoints_sorted = keypoints;
100 std::sort(keypoints_sorted.begin(), keypoints_sorted.end());
101 std::map<int, int> keypoints_loc;
102 for (int i = 0; i < keypoints.size(); i++) {
103 keypoints_loc.insert({keypoints[i], i});
104 }
105 if (keypoints.size() == 1) {
106 std::fill(result.begin(), result.end(), pos[0]);
107 return result;
108 }
109 if (keypoints_sorted[keypoints_sorted.size() - 1] != num_points - 1) {
110 keypoints_sorted.push_back(num_points - 1);
111 keypoints_loc.insert({num_points - 1, static_cast<int>(keypoints.size())});
112 pos.push_back(pos[pos.size() - 1]);
113 }
114 for (int i = 0; i < keypoints_sorted.size() - 1; i++) {
115 int keypoint = keypoints_sorted[i];
116 int keypoint_idx = keypoints_loc[keypoints_sorted[i]];
117 int next_keypoint = keypoints_sorted[i + 1];
118 int next_keypoint_idx = keypoints_loc[keypoints_sorted[i + 1]];
119 std::vector<vec3> curr_positions = linspace(pos[keypoint_idx], pos[next_keypoint_idx], next_keypoint - keypoint + 1);
120 for (int j = 0; j < next_keypoint - keypoint + 1; j++) {
121 int idx = j + keypoint;
122 result[idx] = curr_positions[j];
123 }
124 }
125 return result;
126}
127
128void toggle_button(const char *str_id, bool *v) {
129#ifdef ENABLE_HELIOS_VISUALIZER
130 ImVec2 p = ImGui::GetCursorScreenPos();
131 ImDrawList *draw_list = ImGui::GetWindowDrawList();
132
133 float height = ImGui::GetFrameHeight();
134 float width = height * 1.55f;
135 float radius = height * 0.50f;
136
137 ImGui::InvisibleButton(str_id, ImVec2(width, height));
138 if (ImGui::IsItemClicked())
139 *v = !*v;
140
141 float t = *v ? 1.0f : 0.0f;
142
143 ImGuiContext &g = *GImGui;
144 const float ANIM_SPEED = 0.08f;
145 if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) // && g.LastActiveIdTimer < ANIM_SPEED)
146 {
147 float t_anim = ImSaturate(g.LastActiveIdTimer / ANIM_SPEED);
148 t = *v ? (t_anim) : (1.0f - t_anim);
149 }
150
151 ImU32 col_bg;
152 if (ImGui::IsItemHovered())
153 col_bg = ImGui::GetColorU32(ImLerp(ImVec4(0.78f, 0.78f, 0.78f, 1.0f), ImVec4(0.64f, 0.83f, 0.34f, 1.0f), t));
154 else
155 col_bg = ImGui::GetColorU32(ImLerp(ImVec4(0.85f, 0.85f, 0.85f, 1.0f), ImVec4(0.56f, 0.83f, 0.26f, 1.0f), t));
156
157 draw_list->AddRectFilled(p, ImVec2(p.x + width, p.y + height), col_bg, height * 0.5f);
158 draw_list->AddCircleFilled(ImVec2(p.x + radius + t * (width - radius * 2.0f), p.y + radius), radius - 1.5f, IM_COL32(255, 255, 255, 255));
159#endif // HELIOS_VISUALIZER
160}
161
162// Global flag to track NFD corruption
163static bool nfd_corrupted_imgui = false;
164
165std::string file_dialog() {
166 std::string file_name;
167#ifdef ENABLE_HELIOS_VISUALIZER
168#ifdef _WIN32
169 // save CWD
170 char CWD[MAX_PATH];
171 GetCurrentDirectory(MAX_PATH, CWD);
172
173 OPENFILENAME ofn;
174 char szFile[260] = {0};
175
176 ZeroMemory(&ofn, sizeof(ofn));
177 ofn.lStructSize = sizeof(ofn);
178 ofn.hwndOwner = nullptr;
179 ofn.lpstrFile = szFile;
180 ofn.nMaxFile = sizeof(szFile);
181 ofn.lpstrFilter = "All Files\0*.*\0Text Files\0*.txt\0";
182 ofn.nFilterIndex = 1;
183 ofn.lpstrFileTitle = nullptr;
184 ofn.nMaxFileTitle = 0;
185 ofn.lpstrInitialDir = nullptr;
186 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
187
188 if (GetOpenFileName(&ofn)) {
189 std::cout << "Selected file: " << ofn.lpstrFile << std::endl;
190 } else {
191 std::cout << "No file selected." << std::endl;
192 return "";
193 }
194
195 // correct CWD
196 SetCurrentDirectory(CWD);
197
198 file_name = (std::string) ofn.lpstrFile;
199#elif defined(__APPLE__)
200 nfdchar_t *outPath = nullptr;
201 nfdresult_t result = NFD_OpenDialog(nullptr, nullptr, &outPath);
202
203 if (result == NFD_OKAY) {
204 // puts("Success!");
205 // puts(outPath);
206 file_name = std::string(outPath);
207 free(outPath);
208 } else if (result == NFD_CANCEL) {
209 puts("User pressed cancel.");
210 } else {
211 // printf("Error: %s\n", NFD_GetError() );
212 std::cout << "Error: " << NFD_GetError() << std::endl;
213 }
214#elif defined(__linux__)
215 nfdchar_t *outPath = nullptr;
216 nfdresult_t result = NFD_OpenDialog(nullptr, nullptr, &outPath);
217
218 if (result == NFD_OKAY) {
219 puts("Success!");
220 puts(outPath);
221 file_name = std::string(outPath);
222 free(outPath);
223 } else if (result == NFD_CANCEL) {
224 puts("User pressed cancel.");
225 } else {
226 // printf("Error: %s\n", NFD_GetError() );
227 std::cout << "Error: " << NFD_GetError() << std::endl;
228 }
229#endif
230
231#endif
232
233 return file_name;
234}
235
236
237std::string save_as_file_dialog(std::vector<std::string> extensions) {
238 std::string file_name;
239#ifdef ENABLE_HELIOS_VISUALIZER
240#ifdef _WIN32
241 // save CWD
242 char CWD[MAX_PATH];
243 GetCurrentDirectory(MAX_PATH, CWD);
244
245 OPENFILENAME ofn;
246 char szFile[260] = {0};
247
248 ZeroMemory(&ofn, sizeof(ofn));
249 ofn.lStructSize = sizeof(ofn);
250 ofn.hwndOwner = nullptr;
251 ofn.lpstrFile = szFile;
252 ofn.nMaxFile = sizeof(szFile);
253 std::string filterList = "";
254 for (std::string extension: extensions) {
255 std::string ext_lower = extension;
256 std::string ext_upper = extension;
257 std::transform(ext_lower.begin(), ext_lower.end(), ext_lower.begin(), ::tolower);
258 std::transform(ext_upper.begin(), ext_upper.end(), ext_upper.begin(), ::toupper);
259 filterList += ext_upper + " Files (*." + ext_lower + ")";
260 filterList += '\0';
261 filterList += "*." + ext_lower;
262 filterList += '\0';
263 }
264 filterList += '\0';
265 ofn.lpstrFilter = filterList.c_str();
266 ofn.nFilterIndex = 1;
267 ofn.lpstrFileTitle = nullptr;
268 ofn.nMaxFileTitle = 0;
269 ofn.lpstrInitialDir = nullptr;
270 ofn.Flags = OFN_PATHMUSTEXIST;
271
272 if (GetSaveFileName(&ofn)) {
273 std::cout << "Selected file: " << ofn.lpstrFile << std::endl;
274 } else {
275 std::cout << "No file selected." << std::endl;
276 return "";
277 }
278
279 std::string ext_ = extensions[ofn.nFilterIndex - 1];
280 std::transform(ext_.begin(), ext_.end(), ext_.begin(), ::tolower);
281 std::string ext = "." + ext_;
282
283 // correct CWD
284 SetCurrentDirectory(CWD);
285
286 file_name = (std::string) ofn.lpstrFile;
287
288 std::filesystem::path file_path(file_name);
289 if (file_path.extension().empty()) {
290 file_path.replace_extension(ext);
291 file_name = file_path.string();
292 }
293#elif defined(__APPLE__)
294 nfdchar_t *outPath = nullptr;
295 std::string filterList_ = "";
296 for (std::string extension: extensions) {
297 std::string ext_lower = extension;
298 std::transform(ext_lower.begin(), ext_lower.end(), ext_lower.begin(), ::tolower);
299 filterList_ += ext_lower + ",";
300 }
301 if (!filterList_.empty() && filterList_.back() == ',')
302 filterList_.pop_back();
303 const nfdchar_t *filterList = filterList_.c_str();
304 nfdresult_t result = NFD_SaveDialog(filterList, nullptr, &outPath);
305
306 if (result == NFD_OKAY) {
307 puts("Success!");
308 puts(outPath);
309 file_name = std::string(outPath);
310 free(outPath);
311
312 std::string ext_ = extensions[0];
313 std::transform(ext_.begin(), ext_.end(), ext_.begin(), ::tolower);
314 std::string ext = "." + ext_;
315 if (file_name.find('.') == std::string::npos)
316 file_name += ext;
317 } else if (result == NFD_CANCEL) {
318 puts("User pressed cancel.");
319 } else {
320 // printf("Error: %s\n", NFD_GetError() );
321 std::cout << "Error: " << NFD_GetError() << std::endl;
322 }
323#elif defined(__linux__)
324 nfdchar_t *outPath = nullptr;
325 std::string filterList_ = "";
326 for (std::string extension: extensions) {
327 std::string ext_lower = extension;
328 std::transform(ext_lower.begin(), ext_lower.end(), ext_lower.begin(), ::tolower);
329 filterList_ += ext_lower + ",";
330 }
331 if (!filterList_.empty() && filterList_.back() == ',')
332 filterList_.pop_back();
333 const nfdchar_t *filterList = filterList_.c_str();
334 nfdresult_t result = NFD_SaveDialog(filterList, nullptr, &outPath);
335
336 if (result == NFD_OKAY) {
337 puts("Success!");
338 puts(outPath);
339 file_name = std::string(outPath);
340 free(outPath);
341
342 std::string ext_ = extensions[0];
343 std::transform(ext_.begin(), ext_.end(), ext_.begin(), ::tolower);
344 std::string ext = "." + ext_;
345 if (file_name.find('.') == std::string::npos)
346 file_name += ext;
347 } else if (result == NFD_CANCEL) {
348 puts("User pressed cancel.");
349 } else {
350 // printf("Error: %s\n", NFD_GetError() );
351 std::cout << "Error: " << NFD_GetError() << std::endl;
352 }
353#endif
354#endif
355
356 return file_name;
357}
358
359
360std::vector<std::string> get_xml_node_values(const std::string &xml_input, const std::string &name, const std::string &parent) {
361 int counter = 0;
362 pugi::xml_document xml_library_doc;
363 std::vector<std::string> labels_vec{};
364 std::string xml_library_error = "Failed to load XML Library file";
365 if (!open_xml_file(xml_input, xml_library_doc, xml_library_error)) {
366 helios_runtime_error(xml_library_error);
367 }
368 pugi::xml_node helios = xml_library_doc.child("helios");
369 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
370 std::string default_value = "";
371 if (!p.attribute(name.c_str()).empty()) {
372 const char *node_str = p.attribute(name.c_str()).value();
373 default_value = (std::string) node_str;
374 }
375 labels_vec.push_back(default_value);
376 counter++;
377 }
378 return labels_vec;
379}
380
381
382void ProjectBuilder::deleteArrows() {
383 for (auto &arrow_vec: arrow_dict) {
384 for (std::vector<uint> arrow: arrow_vec.second) {
385 context->deletePrimitive(arrow);
386 }
387 }
388 arrow_dict.clear();
389}
390
391
392void ProjectBuilder::updateArrows() {
393#ifdef ENABLE_RADIATION_MODEL
394 for (auto rig_label_: rig_labels_set) {
395 arrow_count = 0;
396 std::string current_rig = rig_label_;
397 arrow_dict[current_rig] = std::vector<std::vector<uint>>{};
398 for (int i = 1; i < camera_position_vec[rig_dict[current_rig]].size(); i++) {
399 vec3 arrow_pos = camera_position_vec[rig_dict[current_rig]][i - 1];
400 vec3 arrow_direction_vec = arrow_pos - camera_position_vec[rig_dict[current_rig]][i];
401 SphericalCoord arrow_direction_sph = cart2sphere(arrow_direction_vec);
402 vec3 arrow_scale(0.35, 0.35, 0.35);
403 arrow_dict[current_rig].push_back(context->loadOBJ("plugins/radiation/camera_light_models/Arrow.obj", nullorigin, arrow_scale, nullrotation, RGB::blue, "YUP", true));
404 context->rotatePrimitive(arrow_dict.at(current_rig)[arrow_count], arrow_direction_sph.elevation, "x");
405 context->rotatePrimitive(arrow_dict.at(current_rig)[arrow_count], -arrow_direction_sph.azimuth, "z");
406 context->translatePrimitive(arrow_dict.at(current_rig)[arrow_count], arrow_pos);
407 context->setPrimitiveData(arrow_dict.at(current_rig)[arrow_count], "twosided_flag", uint(3));
408 arrow_count++;
409 }
410 float col[3];
411 RGBcolor rig_color = rig_colors[rig_dict[current_rig]];
412 col[0] = rig_color.r;
413 col[1] = rig_color.g;
414 col[2] = rig_color.b;
415 updateColor(current_rig, "arrow", col);
416 }
417#endif
418}
419
420
421void ProjectBuilder::deleteCameraModels() {
422 for (auto &camera_model: camera_models_dict) {
423 context->deletePrimitive(camera_model.second);
424 }
425 camera_models_dict.clear();
426}
427
428
429void ProjectBuilder::updateCameraModels() {
430#ifdef ENABLE_RADIATION_MODEL
431 for (auto rig_label_: rig_labels_set) {
432 int camera_idx = rig_dict[rig_label_];
433 camera_models_dict[rig_label_] = std::vector<uint>{};
434 vec3 camera_pos = camera_position_vec[camera_idx][0];
435 vec3 camera_direction_vec = camera_lookat_vec[camera_idx][0] - camera_pos;
436 SphericalCoord camera_direction_sph = cart2sphere(camera_direction_vec);
437 vec3 camera_scale(1.0, 1.0, 1.0);
438 camera_models_dict[rig_label_] = context->loadOBJ("plugins/radiation/camera_light_models/Camera.obj", nullorigin, camera_scale, nullrotation, RGB::blue, "ZUP", true);
439 context->rotatePrimitive(camera_models_dict.at(rig_label_), camera_direction_sph.elevation, "x");
440 context->rotatePrimitive(camera_models_dict.at(rig_label_), -camera_direction_sph.azimuth, "z");
441 context->translatePrimitive(camera_models_dict.at(rig_label_), camera_pos);
442 context->setPrimitiveData(camera_models_dict.at(rig_label_), "twosided_flag", uint(3));
443 float col[3];
444 RGBcolor rig_color = rig_colors[camera_idx];
445 col[0] = rig_color.r;
446 col[1] = rig_color.g;
447 col[2] = rig_color.b;
448 updateColor(rig_label_, "camera", col);
449 }
450#endif
451}
452
453
454void ProjectBuilder::updatePrimitiveTypes() {
455 std::vector<uint> allUUIDs = context->getAllUUIDs();
456 // Clear current primitive data
457 primitive_names.clear();
458 primitive_names_set.clear();
459 primitive_UUIDs.clear();
460 // primitive_continuous.clear();
461 // primitive_values.clear();
462 // primitive_spectra.clear();
463 //
464 primitive_names.push_back("All");
465 primitive_names_set.insert("All");
466 // primitive_continuous.insert({"All", {false, false, false}});
467 // primitive_spectra.insert({"All", {reflectivity_spectrum, transmissivity_spectrum, emissivity_spectrum}});
468 for (auto &primitive_UUID: allUUIDs) {
469 std::string default_value;
470 if (context->doesPrimitiveDataExist(primitive_UUID, "object_label")) {
471 context->getPrimitiveData(primitive_UUID, "object_label", default_value);
472 if (primitive_names_set.find(default_value) == primitive_names_set.end()) {
473 primitive_names.push_back(default_value);
474 primitive_names_set.insert(default_value);
475 }
476 if (primitive_UUIDs.find(default_value) == primitive_UUIDs.end()) {
477 std::vector<uint> new_UUIDs;
478 // primitive_addresses[default_value] = &new_UUIDs;
479 primitive_UUIDs.insert({default_value, new_UUIDs});
480 }
481 primitive_UUIDs[default_value].push_back(primitive_UUID);
482 if (primitive_continuous.find(default_value) == primitive_continuous.end()) {
483 primitive_continuous.insert({default_value, {false, false, false}});
484 for (std::string band: bandlabels) {
485 primitive_values[band].insert({default_value, {reflectivity, transmissivity, emissivity}});
486 }
487 primitive_spectra.insert({default_value, {reflectivity_spectrum, transmissivity_spectrum, emissivity_spectrum}});
488 }
489 }
490 current_primitive = "All";
491 }
492 // for (auto it = bounding_boxes.begin(); it != bounding_boxes.end(); /* no increment here */) {
493 // if (primitive_names_set.find(it->first) == primitive_names_set.end()) {
494 // it = bounding_boxes.erase(it);
495 // }else {
496 // ++it;
497 // }
498 // }
499 // for (auto& prim : primitive_names_set){
500 // if (prim == "All"){
501 // continue;
502 // }
503 // if (bounding_boxes.find(prim) == bounding_boxes.end()){
504 // bounding_boxes[prim] = false;
505 // }
506 // }
507 // context->setPrimitiveData
508 // context->setPrimitiveData(); type uint or int
509}
510
511
512void ProjectBuilder::updateDataGroups() {
513 data_groups.clear();
514 context->getUniqueObjectDataValues("data_group", data_groups);
515 data_groups_set.clear();
516 data_groups_set.insert("All");
517 for (auto &group: data_groups) {
518 data_groups_set.insert(group);
519 }
520}
521
522
524 for (std::pair<std::string, std::vector<uint>> primitive_pair: primitive_UUIDs) {
525 if (primitive_continuous[primitive_pair.first].empty())
526 continue;
527 if (!primitive_continuous[primitive_pair.first][0]) {
528 for (std::string band: bandlabels) {
529 float reflectivity = primitive_values[band][primitive_pair.first][0];
530 std::string reflectivity_band = "reflectivity_" + band;
531 context->setPrimitiveData(primitive_pair.second, reflectivity_band.c_str(), reflectivity);
532 }
533 } else {
534 std::string reflectivity_spectrum = primitive_spectra[primitive_pair.first][0];
535 if (!reflectivity_spectrum.empty()) {
536 context->setPrimitiveData(primitive_UUIDs[primitive_pair.first], "reflectivity_spectrum", reflectivity_spectrum);
537 } else {
538 std::cout << "WARNING: No value given for '" << primitive_pair.first << "_reflectivity_spectrum'. Assuming " << primitive_pair.first << " primitives are black across all shortwave bands." << std::endl;
539 }
540 }
541 if (!primitive_continuous[primitive_pair.first][1]) {
542 for (std::string band: bandlabels) {
543 float transmissivity = primitive_values[band][primitive_pair.first][1];
544 std::string transmissivity_band = "transmissivity_" + band;
545 context->setPrimitiveData(primitive_pair.second, transmissivity_band.c_str(), transmissivity);
546 }
547 } else {
548 std::string transmissivity_spectrum = primitive_spectra[primitive_pair.first][1];
549 if (!transmissivity_spectrum.empty()) {
550 context->setPrimitiveData(primitive_UUIDs[primitive_pair.first], "transmissivity_spectrum", transmissivity_spectrum);
551 } else {
552 std::cout << "WARNING: No value given for '" << primitive_pair.first << "_transmissivity_spectrum'. Assuming " << primitive_pair.first << " primitives are black across all shortwave bands." << std::endl;
553 }
554 }
555 if (!primitive_continuous[primitive_pair.first][2]) {
556 for (std::string band: bandlabels) {
557 if (bandlabels_set_emissivity.find(band) != bandlabels_set_emissivity.end())
558 continue;
559 float emissivity = primitive_values[band][primitive_pair.first][2];
560 std::string emissivity_band = "emissivity_" + band;
561 context->setPrimitiveData(primitive_pair.second, emissivity_band.c_str(), emissivity);
562 }
563 } else {
564 std::string emissivity_spectrum = primitive_spectra[primitive_pair.first][2];
565 if (!emissivity_spectrum.empty()) {
566 context->setPrimitiveData(primitive_UUIDs[primitive_pair.first], "emissivity_spectrum", emissivity_spectrum);
567 } else {
568 std::cout << "WARNING: No value given for '" << primitive_pair.first << "_emissivity_spectrum'. Assuming " << primitive_pair.first << " primitives are black across all shortwave bands." << std::endl;
569 }
570 }
571 }
572 std::vector<uint> all_UUIDs = context->getAllUUIDs();
573 for (uint UUID: all_UUIDs) {
574 uint parentObjID = context->getPrimitiveParentObjectID(UUID);
575 if (!context->doesObjectExist(parentObjID) || !context->doesObjectDataExist(parentObjID, "data_group"))
576 continue;
577 // Get data group of UUID
578 std::string curr_data_group;
579 context->getObjectData(parentObjID, "data_group", curr_data_group);
580 // Get primitive type of UUID
581 std::string curr_prim_type;
582 if (context->doesPrimitiveDataExist(UUID, "object_label")) {
583 context->getPrimitiveData(UUID, "object_label", curr_prim_type);
584 } else {
585 curr_prim_type = "All";
586 }
587 if (primitive_continuous_dict[curr_data_group][curr_prim_type].empty())
588 continue;
589 if (!primitive_continuous_dict[curr_data_group][curr_prim_type][0]) {
590 for (std::string band: bandlabels) {
591 float reflectivity = primitive_values_dict[curr_data_group][band][curr_prim_type][0];
592 std::string reflectivity_band = "reflectivity_" + band;
593 context->setPrimitiveData(UUID, reflectivity_band.c_str(), reflectivity);
594 }
595 } else {
596 std::string reflectivity_spectrum = primitive_spectra_dict[curr_data_group][curr_prim_type][0];
597 if (!reflectivity_spectrum.empty()) {
598 context->setPrimitiveData(UUID, "reflectivity_spectrum", reflectivity_spectrum);
599 } else {
600 std::cout << "WARNING: No value given for '" << curr_prim_type << "_reflectivity_spectrum'. Assuming " << curr_prim_type << " primitives are black across all shortwave bands." << std::endl;
601 }
602 }
603 if (!primitive_continuous_dict[curr_data_group][curr_prim_type][1]) {
604 for (std::string band: bandlabels) {
605 float transmissivity = primitive_values_dict[curr_data_group][band][curr_prim_type][1];
606 std::string transmissivity_band = "transmissivity_" + band;
607 context->setPrimitiveData(UUID, transmissivity_band.c_str(), transmissivity);
608 }
609 } else {
610 std::string transmissivity_spectrum = primitive_spectra_dict[curr_data_group][curr_prim_type][1];
611 if (!transmissivity_spectrum.empty()) {
612 context->setPrimitiveData(UUID, "transmissivity_spectrum", transmissivity_spectrum);
613 } else {
614 std::cout << "WARNING: No value given for '" << curr_prim_type << "_transmissivity_spectrum'. Assuming " << curr_prim_type << " primitives are black across all shortwave bands." << std::endl;
615 }
616 }
617 if (!primitive_continuous_dict[curr_data_group][curr_prim_type][2]) {
618 for (std::string band: bandlabels) {
619 if (bandlabels_set_emissivity.find(band) != bandlabels_set_emissivity.end())
620 continue;
621 float emissivity = primitive_values_dict[curr_data_group][band][curr_prim_type][2];
622 std::string emissivity_band = "emissivity_" + band;
623 context->setPrimitiveData(UUID, emissivity_band.c_str(), emissivity);
624 }
625 } else {
626 std::string emissivity_spectrum = primitive_spectra_dict[curr_data_group][curr_prim_type][2];
627 if (!emissivity_spectrum.empty()) {
628 context->setPrimitiveData(UUID, "emissivity_spectrum", emissivity_spectrum);
629 } else {
630 std::cout << "WARNING: No value given for '" << curr_prim_type << "_emissivity_spectrum'. Assuming " << curr_prim_type << " primitives are black across all shortwave bands." << std::endl;
631 }
632 }
633 }
634#ifdef ENABLE_RADIATION_MODEL
636#endif
637}
638
640#ifdef ENABLE_RADIATION_MODEL
641 for (std::string rig_label: rig_labels_set) {
642 int rig_index = rig_dict[rig_label];
643 for (std::string rig_camera_label: rig_camera_labels[rig_index]) {
644 int camera_index = camera_dict[rig_camera_label];
645
646 /* Load properties of camera */
647 delete cameraproperties; // Delete previous allocation to prevent memory leak
649 cameraproperties->camera_resolution = camera_resolutions[camera_index];
650 cameraproperties->focal_plane_distance = focal_plane_distances[camera_index];
651 cameraproperties->lens_diameter = lens_diameters[camera_index];
652 cameraproperties->FOV_aspect_ratio = FOV_aspect_ratios[camera_index];
653 cameraproperties->HFOV = HFOVs[camera_index];
654
655 /* Create new camera */
656 std::string camera_label_ = rig_label + "_" + rig_camera_label;
657 vec3 camera_position_ = camera_positions[rig_index];
658 vec3 camera_lookat_ = camera_lookats[rig_index];
659 radiation->addRadiationCamera(camera_label_, bandlabels, camera_position_, camera_lookat_, *cameraproperties, 100);
660 for (auto &band: bandlabels) {
661 radiation->setCameraSpectralResponse(camera_label_, band, camera_calibrations[camera_index][band]);
662 }
664 }
665 }
666 for (std::string band_group_name: band_group_names) {
667 bandGroup curr_band_group = band_group_lookup[band_group_name];
668 if (!curr_band_group.grayscale) {
669 radiation->runBand(curr_band_group.bands);
670 } else {
671 radiation->runBand(std::vector<std::string>{curr_band_group.bands[0]});
672 }
673 }
674#endif // RADIATION_MODEL
675}
676
678#ifdef ENABLE_RADIATION_MODEL
679 deleteArrows();
680 deleteCameraModels();
681 randomize(true);
683 for (int _ = 0; _ < num_recordings; _++) {
685 std::string image_dir = "./saved/";
686 std::string image_dir_base = "./saved_";
687 int image_dir_idx = 0;
688 while (std::filesystem::exists(image_dir)) {
689 image_dir = image_dir_base + std::to_string(image_dir_idx) + "/";
690 image_dir_idx++;
691 }
692 std::filesystem::create_directory(image_dir);
693 std::cout << "Saving images to " << image_dir << std::endl;
694 // Create classes.names file
695 std::ofstream classes_names_file(image_dir + "classes.names");
696 if (classes_names_file.is_open()) {
697 std::vector<std::string> classes(bounding_boxes_map.size());
698 for (auto &bbox_pair: bounding_boxes_map) {
699 classes[bbox_pair.second] = bbox_pair.first;
700 }
701 for (std::string cls: classes) {
702 classes_names_file << cls << std::endl;
703 }
704 }
705 //
706 std::vector<uint> temp_lights{};
707 for (std::string rig_label: rig_labels_set) {
708 int rig_index = rig_dict[rig_label];
709 std::vector<vec3> interpolated_camera_positions = interpolate(keypoint_frames[rig_index], camera_position_vec[rig_index], num_images_vec[rig_index]);
710 std::vector<vec3> interpolated_camera_lookats = interpolate(keypoint_frames[rig_index], camera_lookat_vec[rig_index], num_images_vec[rig_index]);
711 // ADD RIG LIGHTS
712 for (std::string light: rig_light_labels[rig_dict[rig_label]]) {
713 int light_idx = light_dict[light];
714 uint new_light_UUID;
715 if (light_types[light_idx] == "sphere") {
716 new_light_UUID = radiation->addSphereRadiationSource(interpolated_camera_positions[0], light_radius_vec[light_idx]);
717 temp_lights.push_back(new_light_UUID);
718 } else if (light_types[light_dict[light]] == "rectangle") {
719 new_light_UUID = radiation->addRectangleRadiationSource(interpolated_camera_positions[0], light_size_vec[light_idx], light_rotation_vec[light_idx]);
720 temp_lights.push_back(new_light_UUID);
721 } else if (light_types[light_dict[light]] == "disk") {
722 new_light_UUID = radiation->addDiskRadiationSource(interpolated_camera_positions[0], light_radius_vec[light_idx], light_rotation_vec[light_idx]);
723 temp_lights.push_back(new_light_UUID);
724 }
725 for (auto &band: bandlabels) {
726 radiation->setSourceFlux(new_light_UUID, band, light_flux_vec[light_idx]);
727 }
728 }
729 // radiation->updateGeometry(); // TODO: figure out why we can't move updateGeometry here
730 // radiation->setSourceFlux(light_UUID, band, flux_value)
731 //
732 for (int i = 0; i < interpolated_camera_positions.size(); i++) {
733 // SET LIGHT POSITIONS
734 for (uint light_ID: temp_lights) {
735 radiation->setSourcePosition(light_ID, interpolated_camera_positions[i]);
736 }
737 // radiation->setSourceFlux(light_UUID, band, flux_value)
738 //
739 for (std::string rig_camera_label: rig_camera_labels[rig_index]) {
740 int camera_index = camera_dict[rig_camera_label];
741 std::string cameralabel = rig_label + "_" + rig_camera_label;
742 radiation->setCameraPosition(cameralabel, interpolated_camera_positions[i]);
743 radiation->setCameraLookat(cameralabel, interpolated_camera_lookats[i]);
744 }
746 for (std::string band_group_name: band_group_names) {
747 bandGroup curr_band_group = band_group_lookup[band_group_name];
748 if (!curr_band_group.grayscale) {
749 radiation->runBand(curr_band_group.bands);
750 } else {
751 radiation->runBand(std::vector<std::string>{curr_band_group.bands[0]});
752 }
753 }
754 for (std::string rig_camera_label: rig_camera_labels[rig_index]) {
755 std::string cameralabel = rig_label + "_" + rig_camera_label;
756 // Write Images
757 for (std::string band_group_name: band_group_names) {
758 bandGroup curr_band_group = band_group_lookup[band_group_name];
759 if (std::find(curr_band_group.bands.begin(), curr_band_group.bands.end(), "red") != curr_band_group.bands.end() &&
760 std::find(curr_band_group.bands.begin(), curr_band_group.bands.end(), "green") != curr_band_group.bands.end() &&
761 std::find(curr_band_group.bands.begin(), curr_band_group.bands.end(), "blue") != curr_band_group.bands.end()) {
762 radiation->applyCameraImageCorrections(cameralabel, "red", "green", "blue");
763 }
764 std::vector<std::string> band_group_vec;
765 if (!curr_band_group.grayscale) {
766 band_group_vec = curr_band_group.bands;
767 } else {
768 band_group_vec = std::vector<std::string>{curr_band_group.bands[0]};
769 }
770 radiation->writeCameraImage(cameralabel, band_group_vec, band_group_name + std::to_string(i), image_dir + rig_label + '/');
771 if (band_group_lookup[band_group_name].norm) {
772 radiation->writeNormCameraImage(cameralabel, band_group_vec, band_group_name + "_norm" + std::to_string(i), image_dir + rig_label + '/');
773 }
774 }
775 if (write_depth[rig_dict[current_rig]])
776 radiation->writeDepthImageData(cameralabel, "depth" + std::to_string(i), image_dir + rig_label + '/');
777 if (write_norm_depth[rig_dict[current_rig]])
778 radiation->writeNormDepthImage(cameralabel, "normdepth" + std::to_string(i), 3, image_dir + rig_label + '/');
779 //
780 // Bounding boxes for all primitive types
781 for (std::string band_group_: band_group_names) {
782 for (std::string primitive_name: primitive_names) {
783 if (!primitive_name.empty()) {
784 primitive_name[0] = std::tolower(static_cast<unsigned char>(primitive_name[0]));
785 }
786 }
787 for (auto &box_pair: bounding_boxes_map) {
788 if (bounding_boxes_object.find(box_pair.first) != bounding_boxes_object.end()) {
789 radiation->writeImageBoundingBoxes_ObjectData(cameralabel, box_pair.first, box_pair.second, band_group_ + std::to_string(i) + "_bbox", "classes.txt", image_dir + rig_label + '/');
790 if (write_segmentation_mask[rig_dict[current_rig]]) {
791 radiation->writeImageSegmentationMasks_ObjectData(camera_label, box_pair.first, box_pair.second, band_group_ + std::to_string(i) + "_mask", image_dir + rig_label + '/', {}, true);
792 }
793 } else if (bounding_boxes_primitive.find(box_pair.first) == bounding_boxes_object.end()) {
794 radiation->writeImageBoundingBoxes(cameralabel, box_pair.first, box_pair.second, band_group_ + std::to_string(i) + "_bbox", "classes.txt", image_dir + rig_label + '/');
795 if (write_segmentation_mask[rig_dict[current_rig]]) {
796 radiation->writeImageSegmentationMasks(camera_label, box_pair.first, box_pair.second, band_group_ + std::to_string(i) + "_mask", image_dir + rig_label + '/', {}, true);
797 }
798 }
799 }
800 }
801 //
802 }
803 }
804 // REMOVE RIG LIGHTS
805 for (uint temp_light: temp_lights) {
806 radiation->deleteRadiationSource(temp_light);
807 }
808 temp_lights.clear();
809 //
810 }
811 randomize(false);
812 }
813 updateArrows();
814 updateCameraModels();
815#ifdef ENABLE_HELIOS_VISUALIZER
817#endif // HELIOS_VISUALIZER
818#endif // RADIATION_MODEL
819}
820
821
823 xmlSetValues();
824#ifdef ENABLE_HELIOS_VISUALIZER
825 const char *font_name = "LCD";
826 visualizer->addTextboxByCenter("LOADING...", vec3(.5, .5, 0), make_SphericalCoord(0, 0), RGB::red, 40, font_name, Visualizer::COORDINATES_WINDOW_NORMALIZED);
829#endif // HELIOS_VISUALIZER
830
831 // Delete plugins BEFORE context - they hold pointers to context
832#ifdef ENABLE_BOUNDARYLAYERCONDUCTANCEMODEL
834 boundarylayerconductance = nullptr;
835#endif // BOUNDARYLAYERCONDUCTANCEMODEL
836#ifdef ENABLE_ENERGYBALANCEMODEL
837 delete energybalancemodel;
838 energybalancemodel = nullptr;
839#endif // ENERGYBALANCEMODEL
840#ifdef ENABLE_SOLARPOSITION
841 delete solarposition;
842 solarposition = nullptr;
843#endif // SOLARPOSITION
844#ifdef ENABLE_RADIATION_MODEL
845 delete radiation;
846 radiation = nullptr;
847 delete cameraproperties;
848 cameraproperties = nullptr;
849#endif // RADIATION_MODEL
850#ifdef ENABLE_CANOPY_GENERATOR
851 delete canopygenerator;
852 canopygenerator = nullptr;
853#endif // CANOPY_GENERATOR
854#ifdef ENABLE_PLANT_ARCHITECTURE
855 delete plantarchitecture;
856 plantarchitecture = nullptr;
857#endif // PLANT_ARCHITECTURE
858
859 // Delete context LAST
860 delete context;
861 context = nullptr;
862
863 buildFromXML();
864 // #ifdef ENABLE_RADIATION_MODEL
865 // radiation->enableCameraModelVisualization();
866 // #endif //RADIATION_MODEL
867#ifdef ENABLE_HELIOS_VISUALIZER
868#ifdef ENABLE_PLANT_ARCHITECTURE
870#endif // PLANT_ARCHITECTURE
871 visualizer->addCoordinateAxes(helios::make_vec3(0, 0, 0.05), helios::make_vec3(1, 1, 1), "positive");
873#endif // HELIOS_VISUALIZER
874}
875
876
878 context = new Context();
879
882
883// if (enable_plantarchitecture){
884#ifdef ENABLE_PLANT_ARCHITECTURE
886#ifdef ENABLE_RADIATION_MODEL
887 plantarchitecture->optionalOutputObjectData(std::vector<std::string>{"plantID", "leafID", "peduncleID", "closedflowerID", "openflowerID", "fruitID", "rank", "age", "carbohydrate_concentration"});
888#endif
889 std::cout << "Loaded PlantArchitecture plugin." << std::endl;
890// }else{
891#else
892 std::cout << "Excluding PlantArchitecture plugin." << std::endl;
893// } //PLANT_ARCHITECTURE
894#endif // PLANT_ARCHITECTURE
895
896 InitializeSimulation(xml_input_file, context);
897
898// if (enable_plantarchitecture){
899#ifdef ENABLE_PLANT_ARCHITECTURE
900 BuildGeometry(xml_input_file, plantarchitecture, context, canopy_IDs, individual_plant_locations);
901 context->getGlobalData("ground_UUIDs", ground_UUIDs);
902// } //PLANT_ARCHITECTURE
903#endif // PLANT_ARCHITECTURE
904
905// if (enable_radiation){
906#ifdef ENABLE_RADIATION_MODEL
908 std::cout << "Loaded Radiation plugin." << std::endl;
909// }else{
910#else
911 std::cout << "Excluding Radiation plugin." << std::endl;
912// } //RADIATION_MODEL
913#endif // RADIATION_MODEL
914
915// if (enable_solarposition){
916#ifdef ENABLE_SOLARPOSITION
918 std::cout << "Loaded SolarPosition plugin." << std::endl;
919// }else{
920#else
921 std::cout << "Excluding SolarPosition plugin." << std::endl;
922// } //SOLARPOSITION
923#endif // SOLARPOSITION
924
925// if (enable_radiation){
926#ifdef ENABLE_RADIATION_MODEL
927 InitializeRadiation(xml_input_file, solarposition, radiation, context);
928// } //RADIATION_MODEL
929#endif // RADIATION_MODEL
930
931// if (enable_energybalance){
932#ifdef ENABLE_ENERGYBALANCEMODEL
934 std::cout << "Loaded EnergyBalance plugin." << std::endl;
935// }else{
936#else
937 std::cout << "Excluding EnergyBalance plugin." << std::endl;
938// } //ENERGYBALANCEMODEL
939#endif // ENERGYBALANCEMODEL
940
941// if (enable_blconductance){
942#ifdef ENABLE_BOUNDARYLAYERCONDUCTANCEMODEL
944 std::cout << "Loaded BoundaryLayerConductance plugin." << std::endl;
945// }else{
946#else
947 std::cout << "Excluding BoundaryLayerConductance plugin." << std::endl;
948// } //BOUNDARYLAYERCONDUCTANCEMODEL
949#endif // BOUNDARYLAYERCONDUCTANCEMODEL
950
951// if (enable_blconductance && enable_energybalance){
952#if defined(ENABLE_ENERGYBALANCEMODEL) && defined(ENABLE_BOUNDARYLAYERCONDUCTANCEMODEL)
953 InitializeEnergyBalance(xml_input_file, boundarylayerconductance, energybalancemodel, context);
954// } //BOUNDARYLAYERCONDUCTANCEMODE && ENERGYBALANCEMODEL
955#endif // BOUNDARYLAYERCONDUCTANCEMODE && ENERGYBALANCEMODEL
956
957#ifdef ENABLE_CANOPY_GENERATOR
959 std::cout << "Loaded CanopyGenerator plugin." << std::endl;
960// }else{
961#else
962 std::cout << "Excluding CanopyGenerator plugin." << std::endl;
963// } //CANOPYGENERATOR
964#endif // CANOPYGENERATOR
965
966 // -- main time loop -- //
967 if (enable_radiation) {
968 assert(context->doesGlobalDataExist("air_turbidity"));
969 context->getGlobalData("air_turbidity", turbidity);
970 }
971
972 if (enable_radiation) {
973 assert(context->doesGlobalDataExist("diffuse_extinction_coeff"));
974 context->getGlobalData("diffuse_extinction_coeff", diffuse_extinction_coeff);
975 }
976
977 if (enable_radiation) {
978 assert(context->doesGlobalDataExist("sun_ID"));
979 context->getGlobalData("sun_ID", sun_ID);
980 }
981
982 // bandlabels = {"red", "green", "blue"};
983
984 if (enable_plantarchitecture) {
985 context->getGlobalData("ground_UUIDs", ground_UUIDs);
986 context->getGlobalData("leaf_UUIDs", leaf_UUIDs);
987
988 primitive_UUIDs["ground"] = ground_UUIDs;
989 primitive_UUIDs["leaf"] = leaf_UUIDs;
990 // assert( !ground_UUIDs.empty() );
991 // assert( !leaf_UUIDs.empty() );
992 context->setPrimitiveData(ground_UUIDs, "object_label", "ground");
993 context->setPrimitiveData(leaf_UUIDs, "object_label", "leaf");
994 }
995
996 // Update reflectivity, transmissivity, & emissivity for each band / primitive_type
997 if (!open_xml_file(xml_input_file, xmldoc, xml_error_string)) {
998 helios_runtime_error(xml_error_string);
999 }
1000 xmlGetValues();
1001 updateGround(); // TODO: add repeat ground to buildGeometry
1002 updatePrimitiveTypes();
1003 updateSpectra(); // TODO: add update geometry at end
1004
1005 ground_area = context->sumPrimitiveSurfaceArea(ground_UUIDs);
1006
1007 timeseries_variables = context->listTimeseriesVariables();
1008
1009 if (timeseries_variables.empty()) {
1010 std::cout << "No timeseries data was loaded. Skipping time loop." << std::endl;
1011 } else {
1012
1013 uint num_time_points = context->getTimeseriesLength(timeseries_variables.front().c_str());
1014 for (uint timestep = 0; timestep < num_time_points; timestep++) {
1015
1016 context->setCurrentTimeseriesPoint(timeseries_variables.front().c_str(), timestep);
1017
1018 std::cout << "Timestep " << timestep << ": " << context->getDate() << " " << context->getTime() << std::endl;
1019
1020 if (context->doesTimeseriesVariableExist("air_temperature")) {
1021 air_temperature = context->queryTimeseriesData("air_temperature", timestep);
1022 }
1023 context->setPrimitiveData(context->getAllUUIDs(), "air_temperature", air_temperature);
1024
1025 if (context->doesTimeseriesVariableExist("air_humidity")) {
1026 air_humidity = context->queryTimeseriesData("air_humidity", timestep);
1027 if (air_humidity > 1) {
1028 // try dividing by 100
1029 air_humidity /= 100.f;
1030 if (air_humidity > 1) {
1031 std::cout << "WARNING: air_humidity must be between 0 and 1. Setting to default value of 0.5." << std::endl;
1032 air_humidity = 0.5f;
1033 } else {
1034 std::cout << "WARNING: air_humidity read from timeseries was greater than 1.0. It was assumed that the given value was in percent and was automatically divided by 100." << std::endl;
1035 }
1036 }
1037 }
1038 context->setPrimitiveData(context->getAllUUIDs(), "air_humidity", air_humidity);
1039
1040#ifdef ENABLE_RADIATION_MODEL
1041 sun_dir_vec = solarposition->getSunDirectionVector();
1042
1043 radiation->setSourcePosition(sun_ID, sun_dir_vec);
1044
1045 if (diffuse_extinction_coeff > 0) {
1046 radiation->setDiffuseRadiationExtinctionCoeff("PAR", diffuse_extinction_coeff, sun_dir_vec);
1047 radiation->setDiffuseRadiationExtinctionCoeff("NIR", diffuse_extinction_coeff, sun_dir_vec);
1048 }
1049
1050 // Set atmospheric conditions first, then use parameter-free getters
1051 solarposition->setAtmosphericConditions(101000, air_temperature, air_humidity, turbidity);
1052 R_PAR_dir = solarposition->getSolarFluxPAR();
1053 R_NIR_dir = solarposition->getSolarFluxNIR();
1055
1056 radiation->setSourceFlux(sun_ID, "PAR", R_PAR_dir * (1.f - fdiff));
1057 radiation->setDiffuseRadiationFlux("PAR", R_PAR_dir * fdiff);
1058 radiation->setSourceFlux(sun_ID, "NIR", R_NIR_dir * (1.f - fdiff));
1059 radiation->setDiffuseRadiationFlux("NIR", R_NIR_dir * fdiff);
1060
1061 // Run the radiation model
1062 radiation->runBand({"PAR", "NIR", "LW"});
1063
1064 std::vector<std::string> new_band_group_vector = {"PAR", "NIR", "LW"};
1065 bandGroup new_band_group{new_band_group_vector, false, false, false};
1066 band_group_lookup.insert({"default", new_band_group});
1067 band_group_names.insert("default");
1068
1069 context->calculatePrimitiveDataAreaWeightedSum(leaf_UUIDs, "radiation_flux_PAR", PAR_absorbed);
1070 PAR_absorbed /= ground_area;
1071
1072 context->calculatePrimitiveDataAreaWeightedSum(leaf_UUIDs, "radiation_flux_NIR", NIR_absorbed);
1073 NIR_absorbed /= ground_area;
1074
1075 context->calculatePrimitiveDataAreaWeightedSum(leaf_UUIDs, "radiation_flux_LW", LW_absorbed);
1076 LW_absorbed /= ground_area;
1077
1078 std::cout << "Absorbed PAR: " << PAR_absorbed << " W/m^2" << std::endl;
1079 std::cout << "Absorbed NIR: " << NIR_absorbed << " W/m^2" << std::endl;
1080 std::cout << "Absorbed LW: " << LW_absorbed << " W/m^2" << std::endl;
1081#endif // ENABLE_RADIATION_MODEL
1082 }
1083 // RIG BLOCK
1084 // *** Loading any XML files needed for cameras *** //
1085 for (auto &xml_file: camera_xml_library_files) {
1086 if (xml_file.empty() || !std::filesystem::exists(xml_file)) {
1087 std::cout << "WARNING: Could not find camera XML library file: " + xml_file << ". Skipping..." << std::endl;
1088 continue;
1089 }
1090 context->loadXML(xml_file.c_str());
1091 }
1092 // *** Loading any XML files needed for lights *** //
1093 for (auto &xml_file: light_xml_library_files) {
1094 if (xml_file.empty() || !std::filesystem::exists(xml_file)) {
1095 std::cout << "WARNING: Could not find light XML library file: " + xml_file << ". Skipping..." << std::endl;
1096 continue;
1097 }
1098 context->loadXML(xml_file.c_str());
1099 }
1100
1101// if (enable_solarposition && enable_radiation){
1102#ifdef ENABLE_RADIATION_MODEL
1103
1104 radiation->setSourceSpectrum(sun_ID, solar_direct_spectrum);
1105
1107 radiation->disableEmission("red");
1108 // radiation->setSourceFlux(sun_ID, "red", 2.f);
1109 radiation->setScatteringDepth("red", 2);
1110
1111 radiation->copyRadiationBand("red", "green");
1112 radiation->copyRadiationBand("red", "blue");
1113
1114 radiation->enforcePeriodicBoundary("xy"); // TODO: make this a user setting
1115// } //SOLARPOSITION && RADIATION_MODEL
1116#endif // SOLARPOSITION && RADIATION_MODEL
1117 }
1118 // RIG BLOCK
1119 num_images = 5;
1120 updateArrows();
1121 updateCameras();
1122 updateCameraModels();
1123
1124 helios = xmldoc.child("helios");
1125
1126 refreshVisualizationTypes();
1127
1128 built = true;
1129}
1130
1131
1132void ProjectBuilder::buildFromXML(std::string xml_path) {
1133 xml_input_file = xml_path;
1134 buildFromXML();
1135}
1136
1137
1138std::map<std::string, int> ProjectBuilder::getNodeLabels(const std::string &name, const std::string &parent, std::vector<std::string> &labels_vec) {
1139 int counter = 0;
1140 std::map<std::string, int> labels_dict = {};
1141 helios = xmldoc.child("helios");
1142 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1143 std::string default_value = "canopy_0";
1144 if (!p.attribute(name.c_str()).empty()) {
1145 const char *node_str = p.attribute(name.c_str()).value();
1146 default_value = (std::string) node_str;
1147 }
1148 labels_vec.push_back(default_value);
1149 labels_dict.insert({default_value, counter});
1150 counter++;
1151 }
1152 return labels_dict;
1153}
1154
1155
1156void ProjectBuilder::getKeypoints(const std::string &name, const std::string &parent, std::vector<std::vector<int>> &keypoints) {
1157 helios = xmldoc.child("helios");
1158 const char *rig_ = "rig";
1159 for (pugi::xml_node rig = helios.child(rig_); rig; rig = rig.next_sibling(rig_)) {
1160 int count = 0;
1161 std::vector<int> curr_keypoints;
1162 for (pugi::xml_node p = rig.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1163 std::string default_value = std::to_string(count);
1164 if (!p.attribute(name.c_str()).empty()) {
1165 const char *node_str = p.attribute(name.c_str()).value();
1166 default_value = (std::string) node_str;
1167 }
1168 std::stringstream keypoint_value;
1169 keypoint_value << default_value.c_str();
1170 int keypoint_;
1171 keypoint_value >> keypoint_;
1172 curr_keypoints.push_back(keypoint_);
1173 count++;
1174 }
1175 keypoints.push_back(curr_keypoints);
1176 }
1177}
1178
1179void ProjectBuilder::setKeypoints(const std::string &name, const std::string &parent, std::vector<std::vector<int>> &keypoints) {
1180 helios = xmldoc.child("helios");
1181 const char *rig_ = "rig";
1182 int rig_count = 0;
1183 for (pugi::xml_node rig = helios.child(rig_); rig; rig = rig.next_sibling(rig_)) {
1184 int count = 0;
1185 for (pugi::xml_node p = rig.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1186 std::string default_value = std::to_string(count);
1187 p.append_attribute(name.c_str());
1188 p.attribute(name.c_str()).set_value(keypoints[rig_count][count]);
1189 count++;
1190 }
1191 rig_count++;
1192 }
1193} // TODO: test this function
1194
1195void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, int &default_value) {
1196 helios = xmldoc.child("helios");
1197 pugi::xml_node p = helios;
1198 if (parent != "helios") {
1199 p = helios.child(parent.c_str());
1200 }
1201 pugi::xml_node node;
1202 node = p.child(name.c_str());
1203 if (node.empty()) {
1204 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1205 } else {
1206 const char *node_str = node.child_value();
1207 if (!parse_int(node_str, default_value)) {
1208 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1209 } else if (default_value < 0) {
1210 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than or equal to 0.");
1211 }
1212 }
1213}
1214
1215void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, float &default_value) {
1216 helios = xmldoc.child("helios");
1217 pugi::xml_node p = helios;
1218 if (parent != "helios") {
1219 p = helios.child(parent.c_str());
1220 }
1221 pugi::xml_node node;
1222 node = p.child(name.c_str());
1223 if (node.empty()) {
1224 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1225 } else {
1226 const char *node_str = node.child_value();
1227 if (!parse_float(node_str, default_value)) {
1228 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1229 }
1230 // else if( default_value<0 ){
1231 // helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than or equal to 0.");
1232 // }
1233 }
1234}
1235
1236void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, std::string &default_value) {
1237 helios = xmldoc.child("helios");
1238 pugi::xml_node p = helios;
1239 if (parent != "helios") {
1240 p = helios.child(parent.c_str());
1241 }
1242 pugi::xml_node node;
1243 node = p.child(name.c_str());
1244 if (node.empty()) {
1245 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1246 } else {
1247 const char *node_str = node.child_value();
1248 default_value = node_str;
1249 }
1250}
1251
1252void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, vec2 &default_value) {
1253 helios = xmldoc.child("helios");
1254 pugi::xml_node p = helios;
1255 if (parent != "helios") {
1256 p = helios.child(parent.c_str());
1257 }
1258 pugi::xml_node node;
1259 node = p.child(name.c_str());
1260 if (node.empty()) {
1261 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1262 } else {
1263 const char *node_str = node.child_value();
1264 if (!parse_vec2(node_str, default_value)) {
1265 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1266 } else if (default_value.x <= 0 || default_value.y <= 0) {
1267 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than 0.");
1268 }
1269 }
1270}
1271
1272void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, vec3 &default_value) {
1273 helios = xmldoc.child("helios");
1274 pugi::xml_node p = helios;
1275 if (parent != "helios") {
1276 p = helios.child(parent.c_str());
1277 }
1278 pugi::xml_node node;
1279 node = p.child(name.c_str());
1280 if (node.empty()) {
1281 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1282 } else {
1283 const char *node_str = node.child_value();
1284 if (!parse_vec3(node_str, default_value)) {
1285 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1286 }
1287 }
1288}
1289
1290
1291void ProjectBuilder::xmlGetValue(const std::string &name, const std::string &parent, int2 &default_value) {
1292 helios = xmldoc.child("helios");
1293 pugi::xml_node p = helios;
1294 if (parent != "helios") {
1295 p = helios.child(parent.c_str());
1296 }
1297 pugi::xml_node node;
1298 node = p.child(name.c_str());
1299 if (node.empty()) {
1300 std::cout << "WARNING: No value given for '" << name << "'. Using default value of " << default_value << std::endl;
1301 } else {
1302 const char *node_str = node.child_value();
1303 if (!parse_int2(node_str, default_value)) {
1304 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1305 } else if (default_value.x <= 0 || default_value.y <= 0) {
1306 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than 0.");
1307 }
1308 }
1309}
1310
1311
1312void ProjectBuilder::xmlGetDistribution(const std::string &name, const std::string &parent, distribution &distribution) {
1313 helios = xmldoc.child("helios");
1314 pugi::xml_node p = helios;
1315 if (parent != "helios") {
1316 p = helios.child(parent.c_str());
1317 }
1318 pugi::xml_node node;
1319 node = p.child(name.c_str());
1320 if (node.empty()) {
1321 std::cout << "WARNING: No distribution given for '" << name << "'. Using default distribution of N/A." << std::endl;
1322 distribution.flag = -1;
1323 } else {
1324 const char *node_str = node.child_value();
1325 if (!parse_distribution(node_str, distribution)) {
1326 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1327 }
1328 }
1329}
1330
1331
1332void ProjectBuilder::xmlSetDistribution(const std::string &name, const std::string &parent, distribution &distribution) {
1333 helios = xmldoc.child("helios");
1334 pugi::xml_node p = helios;
1335 if (parent != "helios") {
1336 p = helios.child(parent.c_str());
1337 }
1338 pugi::xml_node node;
1339 node = p.child(name.c_str());
1340 if (!node) {
1341 node = p.append_child(name.c_str());
1342 }
1343 std::string dist_type;
1344 std::string param_1;
1345 std::string param_2;
1346 std::string repeat;
1347 if (distribution.flag == 0) {
1348 dist_type = "normal";
1349 param_1 = std::to_string(distribution.dist.normal->mean());
1350 param_2 = std::to_string(distribution.dist.normal->stddev());
1351 repeat = std::to_string(distribution.repeat);
1352 } else if (distribution.flag == 1) {
1353 dist_type = "uniform";
1354 param_1 = std::to_string(distribution.dist.uniform->a());
1355 param_2 = std::to_string(distribution.dist.uniform->b());
1356 repeat = std::to_string(distribution.repeat);
1357 } else if (distribution.flag == 2) {
1358 dist_type = "weibull";
1359 param_1 = std::to_string(distribution.dist.weibull->a());
1360 param_2 = std::to_string(distribution.dist.weibull->b());
1361 repeat = std::to_string(distribution.repeat);
1362 } else if (distribution.flag == -1) {
1363 dist_type = "N/A";
1364 param_1 = "0";
1365 param_2 = "0";
1366 repeat = "0";
1367 }
1368 node.text().set((dist_type + " " + param_1 + " " + param_2 + " " + repeat).c_str());
1369}
1370
1371
1372bool parse_distribution(const std::string &input_string, distribution &converted_distribution) {
1373 std::istringstream vecstream(input_string);
1374 std::vector<std::string> tmp_s(4);
1375 vecstream >> tmp_s[0];
1376 vecstream >> tmp_s[1];
1377 vecstream >> tmp_s[2];
1378 vecstream >> tmp_s[3];
1379 std::string dist_type;
1380 std::vector<float> dist_params = {0.0, 0.0};
1381 int repeat = 0;
1382 if (!parse_float(tmp_s[1], dist_params[0]) || !parse_float(tmp_s[2], dist_params[1]) || !parse_int(tmp_s[3], repeat)) {
1383 return false;
1384 }
1385 distUnion dist{};
1386 if (dist_type == "normal") {
1387 dist.normal = new std::normal_distribution<float>;
1388 *dist.normal = std::normal_distribution<float>(dist_params[0], dist_params[1]);
1389 converted_distribution.dist = dist;
1390 converted_distribution.flag = 0;
1391 converted_distribution.repeat = (bool) repeat;
1392 } else if (dist_type == "uniform") {
1393 dist.uniform = new std::uniform_real_distribution<float>;
1394 *dist.uniform = std::uniform_real_distribution<float>(dist_params[0], dist_params[1]);
1395 converted_distribution.dist = dist;
1396 converted_distribution.flag = 1;
1397 converted_distribution.repeat = (bool) repeat;
1398 } else if (dist_type == "weibull") {
1399 dist.weibull = new std::weibull_distribution<float>;
1400 *dist.weibull = std::weibull_distribution<float>(dist_params[0], dist_params[1]);
1401 converted_distribution.dist = dist;
1402 converted_distribution.flag = 2;
1403 converted_distribution.repeat = (bool) repeat;
1404 } else {
1405 converted_distribution.flag = -1;
1406 }
1407 return true;
1408}
1409
1410
1411void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<vec2> &default_vec) {
1412 helios = xmldoc.child("helios");
1413 pugi::xml_node node;
1414 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1415 node = p.child(name.c_str());
1416 if (node.empty()) {
1417 std::cout << "WARNING: No value given for '" << name << "'.";
1418 } else {
1419 const char *node_str = node.child_value();
1420 vec2 default_value;
1421 if (!parse_vec2(node_str, default_value)) {
1422 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1423 }
1424 // else if( default_value.x<=0 || default_value.y<=0 ){
1425 // helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than 0.");
1426 // }
1427 else {
1428 default_vec.push_back(default_value);
1429 }
1430 }
1431 }
1432}
1433
1434
1435void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<vec3> &default_vec) {
1436 helios = xmldoc.child("helios");
1437 pugi::xml_node node;
1438 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1439 node = p.child(name.c_str());
1440 if (node.empty()) {
1441 std::cout << "WARNING: No value given for '" << name << "'.";
1442 } else {
1443 const char *node_str = node.child_value();
1444 vec3 default_value;
1445 if (!parse_vec3(node_str, default_value)) {
1446 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1447 } else {
1448 default_vec.push_back(default_value);
1449 }
1450 }
1451 }
1452}
1453
1454
1455void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<std::string> &default_vec) {
1456 helios = xmldoc.child("helios");
1457 pugi::xml_node node;
1458 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1459 node = p.child(name.c_str());
1460 if (node.empty()) {
1461 std::cout << "WARNING: No value given for '" << name << "'.";
1462 } else {
1463 const char *node_str = node.child_value();
1464 std::string default_value = trim_whitespace(std::string(node_str));
1465 default_vec.push_back(default_value); // Always push to maintain vector size consistency
1466 }
1467 }
1468}
1469
1470
1471void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<float> &default_vec) {
1472 helios = xmldoc.child("helios");
1473 pugi::xml_node node;
1474 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1475 node = p.child(name.c_str());
1476 if (node.empty()) {
1477 std::cout << "WARNING: No value given for '" << name << "'.";
1478 } else {
1479 const char *node_str = node.child_value();
1480 float default_value;
1481 if (!parse_float(node_str, default_value)) {
1482 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1483 } else if (default_value < 0) {
1484 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than or equal to 0.");
1485 } else {
1486 default_vec.push_back(default_value);
1487 }
1488 }
1489 }
1490}
1491
1492
1493void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<int> &default_vec) {
1494 helios = xmldoc.child("helios");
1495 pugi::xml_node node;
1496 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1497 node = p.child(name.c_str());
1498 if (node.empty()) {
1499 std::cout << "WARNING: No value given for '" << name << "'.";
1500 } else {
1501 const char *node_str = node.child_value();
1502 int default_value;
1503 if (!parse_int(node_str, default_value)) {
1504 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1505 } else if (default_value < 0) {
1506 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than or equal to 0.");
1507 } else {
1508 default_vec.push_back(default_value);
1509 }
1510 }
1511 }
1512}
1513
1514
1515void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<int2> &default_vec) {
1516 helios = xmldoc.child("helios");
1517 pugi::xml_node node;
1518 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1519 node = p.child(name.c_str());
1520 if (node.empty()) {
1521 std::cout << "WARNING: No value given for '" << name << "'.";
1522 } else {
1523 const char *node_str = node.child_value();
1524 int2 default_value;
1525 if (!parse_int2(node_str, default_value)) {
1526 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1527 } else if (default_value.x <= 0 || default_value.y <= 0) {
1528 helios_runtime_error("ERROR: Value given for '" + name + "' must be greater than or equal to 0.");
1529 } else {
1530 default_vec.push_back(default_value);
1531 }
1532 }
1533 }
1534}
1535
1536
1537void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<helios::RGBcolor> &default_vec) {
1538 helios = xmldoc.child("helios");
1539 pugi::xml_node node;
1540 for (pugi::xml_node p = helios.child(parent.c_str()); p; p = p.next_sibling(parent.c_str())) {
1541 node = p.child(name.c_str());
1542 if (node.empty()) {
1543 std::cout << "WARNING: No value given for '" << name << "'.";
1544 } else {
1545 const char *node_str = node.child_value();
1546 helios::RGBcolor default_value;
1547 if (!parse_RGBcolor(node_str, default_value)) {
1548 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1549 } else {
1550 default_vec.push_back(default_value);
1551 }
1552 }
1553 }
1554}
1555
1556
1557void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<std::vector<vec3>> &default_vec) {
1558 helios = xmldoc.child("helios");
1559 pugi::xml_node p_;
1560 if (parent != "helios") {
1561 p_ = helios.child(parent.c_str());
1562 } else {
1563 p_ = helios;
1564 }
1565 for (pugi::xml_node p = p_; p; p = p.next_sibling(parent.c_str())) {
1566 std::vector<vec3> curr_vec = {};
1567 for (pugi::xml_node node = p.child(name.c_str()); node; node = node.next_sibling(name.c_str())) {
1568 const char *node_str = node.child_value();
1569 vec3 default_value;
1570 if (!parse_vec3(node_str, default_value)) {
1571 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1572 } else {
1573 curr_vec.push_back(default_value);
1574 }
1575 }
1576 default_vec.push_back(curr_vec);
1577 }
1578}
1579
1580
1581void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::vector<std::set<std::string>> &default_vec) {
1582 helios = xmldoc.child("helios");
1583 pugi::xml_node p_;
1584 if (parent != "helios") {
1585 p_ = helios.child(parent.c_str());
1586 } else {
1587 p_ = helios;
1588 }
1589 for (pugi::xml_node p = p_; p; p = p.next_sibling(parent.c_str())) {
1590 std::set<std::string> curr_vec = {};
1591 for (pugi::xml_node node = p.child(name.c_str()); node; node = node.next_sibling(name.c_str())) {
1592 const char *node_str = node.child_value();
1593 std::string default_value;
1594 if (node.empty()) {
1595 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1596 } else {
1597 default_value = node_str;
1598 curr_vec.insert(default_value);
1599 }
1600 }
1601 default_vec.push_back(curr_vec);
1602 }
1603}
1604
1605
1606void ProjectBuilder::xmlGetValues(const std::string &name, const std::string &parent, std::set<std::string> &default_set) {
1607 helios = xmldoc.child("helios");
1608 pugi::xml_node p_;
1609 if (parent != "helios") {
1610 p_ = helios.child(parent.c_str());
1611 } else {
1612 p_ = helios;
1613 }
1614 for (pugi::xml_node p = p_; p; p = p.next_sibling(parent.c_str())) {
1615 for (pugi::xml_node node = p.child(name.c_str()); node; node = node.next_sibling(name.c_str())) {
1616 const char *node_str = node.child_value();
1617 std::string default_value;
1618 if (node.empty()) {
1619 helios_runtime_error("ERROR: Value given for '" + name + "' could not be parsed.");
1620 } else {
1621 default_value = node_str;
1622 default_set.insert(default_value);
1623 }
1624 }
1625 }
1626}
1627
1628
1629void ProjectBuilder::setNodeLabels(const std::string &name, const std::string &parent, std::set<std::string> &labels_vec) {
1630 int i = 0;
1631 helios = xmldoc.child("helios");
1632
1633 std::set<pugi::xml_node> curr_nodes_set;
1634 for (pugi::xml_node node = helios.child(parent.c_str()); node; node = node.next_sibling(parent.c_str())) {
1635 curr_nodes_set.insert(node);
1636 }
1637 for (auto node: curr_nodes_set) {
1638 node.parent().remove_child(node);
1639 }
1640
1641 std::map<std::string, int> labels_dict = {};
1642 for (auto new_node_label: labels_vec) {
1643 pugi::xml_node new_node = helios.append_child(parent.c_str());
1644 pugi::xml_attribute node_label = new_node.attribute(name.c_str());
1645 node_label.set_value(new_node_label.c_str());
1646 new_node.append_attribute(name.c_str()).set_value(new_node_label.c_str());
1647 }
1648
1649 return;
1650}
1651
1652
1653void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, int &default_value) {
1654 helios = xmldoc.child("helios");
1655 pugi::xml_node p = helios;
1656 if (parent != "helios") {
1657 p = helios.child(parent.c_str());
1658 }
1659 pugi::xml_node node;
1660 node = p.child(name.c_str());
1661 if (!node) {
1662 node = p.append_child(name.c_str());
1663 }
1664 node.text().set(std::to_string(default_value).c_str());
1665}
1666
1667void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, float &default_value) {
1668 helios = xmldoc.child("helios");
1669 pugi::xml_node p = helios;
1670 if (parent != "helios") {
1671 p = helios.child(parent.c_str());
1672 }
1673 pugi::xml_node node;
1674 node = p.child(name.c_str());
1675 if (!node) {
1676 node = p.append_child(name.c_str());
1677 }
1678 node.text().set(std::to_string(default_value).c_str());
1679}
1680
1681void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, std::string &default_value) {
1682 helios = xmldoc.child("helios");
1683 pugi::xml_node p = helios;
1684 if (parent != "helios") {
1685 p = helios.child(parent.c_str());
1686 }
1687 pugi::xml_node node;
1688 node = p.child(name.c_str());
1689 if (!node) {
1690 node = p.append_child(name.c_str());
1691 }
1692 node.text().set(default_value.c_str());
1693}
1694
1695void ProjectBuilder::xmlRemoveField(const std::string &name, const std::string &parent) {
1696 helios = xmldoc.child("helios");
1697 pugi::xml_node p = helios;
1698 if (parent != "helios") {
1699 p = helios.child(parent.c_str());
1700 }
1701 pugi::xml_node node;
1702 node = p.child(name.c_str());
1703 if (node) {
1704 p.remove_child(name.c_str());
1705 }
1706}
1707
1708void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, int2 &default_value) {
1709 helios = xmldoc.child("helios");
1710 pugi::xml_node p = helios;
1711 if (parent != "helios") {
1712 p = helios.child(parent.c_str());
1713 }
1714 pugi::xml_node node;
1715 node = p.child(name.c_str());
1716 if (!node) {
1717 node = p.append_child(name.c_str());
1718 }
1719 node.text().set(vec_to_string(default_value).c_str());
1720}
1721
1722void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, vec2 &default_value) {
1723 helios = xmldoc.child("helios");
1724 pugi::xml_node p = helios;
1725 if (parent != "helios") {
1726 p = helios.child(parent.c_str());
1727 }
1728 pugi::xml_node node;
1729 node = p.child(name.c_str());
1730 if (!node) {
1731 node = p.append_child(name.c_str());
1732 }
1733 node.text().set(vec_to_string(default_value).c_str());
1734}
1735
1736void ProjectBuilder::xmlSetValue(const std::string &name, const std::string &parent, vec3 &default_value) {
1737 helios = xmldoc.child("helios");
1738 pugi::xml_node p = helios;
1739 if (parent != "helios") {
1740 p = helios.child(parent.c_str());
1741 }
1742 pugi::xml_node node;
1743 node = p.child(name.c_str());
1744 if (!node) {
1745 node = p.append_child(name.c_str());
1746 }
1747 node.text().set(vec_to_string(default_value).c_str());
1748}
1749
1750
1751void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<vec2> &values_vec, std::map<std::string, int> &node_map) {
1752 helios = xmldoc.child("helios");
1753
1754 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1755 pugi::xml_node node = p.child(field_name.c_str());
1756 if (!node) {
1757 node = p.append_child(field_name.c_str());
1758 }
1759 pugi::xml_attribute label = p.attribute("label");
1760 int idx = node_map[label.as_string()];
1761 node.text().set(vec_to_string(values_vec[idx]).c_str());
1762 }
1763}
1764
1765
1766void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<vec3> &values_vec, std::map<std::string, int> &node_map) {
1767 helios = xmldoc.child("helios");
1768
1769 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1770 pugi::xml_node node = p.child(field_name.c_str());
1771 if (!node) {
1772 node = p.append_child(field_name.c_str());
1773 }
1774 pugi::xml_attribute label = p.attribute("label");
1775 int idx = node_map[label.as_string()];
1776 node.text().set(vec_to_string(values_vec[idx]).c_str());
1777 }
1778}
1779
1780
1781void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<helios::RGBcolor> &values_vec, std::map<std::string, int> &node_map) {
1782 helios = xmldoc.child("helios");
1783
1784 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1785 pugi::xml_node node = p.child(field_name.c_str());
1786 if (!node) {
1787 node = p.append_child(field_name.c_str());
1788 }
1789 pugi::xml_attribute label = p.attribute("label");
1790 int idx = node_map[label.as_string()];
1791 helios::vec3 default_values_vec;
1792 default_values_vec.x = values_vec[idx].r;
1793 default_values_vec.y = values_vec[idx].g;
1794 default_values_vec.z = values_vec[idx].b;
1795 node.text().set(vec_to_string(default_values_vec).c_str());
1796 }
1797}
1798
1799
1800void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<int2> &values_vec, std::map<std::string, int> &node_map) {
1801 helios = xmldoc.child("helios");
1802
1803 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1804 pugi::xml_node node = p.child(field_name.c_str());
1805 if (!node) {
1806 node = p.append_child(field_name.c_str());
1807 }
1808 pugi::xml_attribute label = p.attribute("label");
1809 int idx = node_map[label.as_string()];
1810 node.text().set(vec_to_string(values_vec[idx]).c_str());
1811 }
1812}
1813
1814
1815void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<std::string> &values_vec, std::map<std::string, int> &node_map) {
1816 helios = xmldoc.child("helios");
1817
1818 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1819 pugi::xml_node node = p.child(field_name.c_str());
1820 if (!node) {
1821 node = p.append_child(field_name.c_str());
1822 }
1823 pugi::xml_attribute label = p.attribute("label");
1824 int idx = node_map[label.as_string()];
1825 node.text().set(values_vec[idx].c_str());
1826 }
1827}
1828
1829
1830void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<int> &values_vec, std::map<std::string, int> &node_map) {
1831 helios = xmldoc.child("helios");
1832
1833 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1834 pugi::xml_node node = p.child(field_name.c_str());
1835 if (!node) {
1836 node = p.append_child(field_name.c_str());
1837 }
1838 pugi::xml_attribute label = p.attribute("label");
1839 int idx = node_map[label.as_string()];
1840 node.text().set(std::to_string(values_vec[idx]).c_str());
1841 }
1842}
1843
1844
1845void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<float> &values_vec, std::map<std::string, int> &node_map) {
1846 helios = xmldoc.child("helios");
1847
1848 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1849 pugi::xml_node node = p.child(field_name.c_str());
1850 if (!node) {
1851 node = p.append_child(field_name.c_str());
1852 }
1853 pugi::xml_attribute label = p.attribute("label");
1854 int idx = node_map[label.as_string()];
1855 node.text().set(std::to_string(values_vec[idx]).c_str());
1856 }
1857}
1858
1859
1860void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<std::vector<vec3>> &values_vec, std::map<std::string, int> &node_map) {
1861 helios = xmldoc.child("helios");
1862
1863 for (pugi::xml_node p = helios.child(node_name.c_str()); p; p = p.next_sibling(node_name.c_str())) {
1864 std::vector<pugi::xml_node> remove = {};
1865 for (pugi::xml_node node = p.child(field_name.c_str()); node; node = node.next_sibling(field_name.c_str())) {
1866 remove.push_back(node);
1867 }
1868 for (pugi::xml_node &node: remove) {
1869 p.remove_child(node);
1870 }
1871 pugi::xml_attribute label = p.attribute("label");
1872 int idx = node_map[label.as_string()];
1873 for (int j = 0; j < values_vec[idx].size(); j++) {
1874 // p.append_child(name.c_str()).set_value(vec_to_string(default_vec[i][j]).c_str());
1875 pugi::xml_node new_node = p.append_child(field_name.c_str());
1876 new_node.text().set(vec_to_string(values_vec[idx][j]).c_str());
1877 }
1878 }
1879}
1880
1881
1882void ProjectBuilder::xmlSetValues(const std::string &field_name, const std::string &node_name, std::vector<std::set<std::string>> &values_vec, std::map<std::string, int> &node_map) {
1883 helios = xmldoc.child("helios");
1884 int i = 0;
1885 pugi::xml_node p_;
1886 if (node_name != "helios") {
1887 p_ = helios.child(node_name.c_str());
1888 } else {
1889 p_ = helios;
1890 }
1891 for (pugi::xml_node p = p_; p; p = p.next_sibling(node_name.c_str())) {
1892 std::vector<pugi::xml_node> remove{};
1893 for (pugi::xml_node node = p.child(field_name.c_str()); node; node = node.next_sibling(field_name.c_str())) {
1894 remove.push_back(node);
1895 }
1896 for (pugi::xml_node &node: remove) {
1897 p.remove_child(node);
1898 }
1899 pugi::xml_attribute label = p.attribute("label");
1900 int idx = node_map[label.as_string()];
1901 for (std::string s: values_vec[idx]) {
1902 // p.append_child(name.c_str()).set_value(s.c_str());
1903 pugi::xml_node new_node = p.append_child(field_name.c_str());
1904 new_node.text().set(s.c_str());
1905 }
1906 }
1907} // TODO: test this function
1908
1909
1910void ProjectBuilder::xmlSetValues(const std::string &name, const std::string &parent, std::set<std::string> &default_set) {
1911 helios = xmldoc.child("helios");
1912 int i = 0;
1913 pugi::xml_node p_;
1914 if (parent != "helios") {
1915 p_ = helios.child(parent.c_str());
1916 } else {
1917 p_ = helios;
1918 }
1919 for (pugi::xml_node p = p_; p; p = p.next_sibling(parent.c_str())) {
1920 std::vector<pugi::xml_node> remove{};
1921 for (pugi::xml_node node = p.child(name.c_str()); node; node = node.next_sibling(name.c_str())) {
1922 remove.push_back(node);
1923 }
1924 for (pugi::xml_node &node: remove) {
1925 p.remove_child(node);
1926 }
1927 for (std::string s: default_set) {
1928 // p.append_child(name.c_str()).set_value(s.c_str());
1929 pugi::xml_node new_node = p.append_child(name.c_str());
1930 new_node.text().set(s.c_str());
1931 }
1932 i++;
1933 }
1934} // TODO: test this function
1935
1936
1938 if (!built) {
1939 std::cout << "Project must be built before running visualize." << std::endl;
1940 return;
1941 }
1942// if (enable_visualizer){
1943#ifdef ENABLE_HELIOS_VISUALIZER
1944 visualizer = new Visualizer(800);
1945 // #ifdef ENABLE_RADIATION_MODEL
1946 // radiation->enableCameraModelVisualization();
1947 // #endif //RADIATION_MODEL
1949
1950 // Uncomment below for interactive
1951 // visualizer.plotInteractive();
1952
1953 visualizer->addCoordinateAxes(helios::make_vec3(0, 0, 0.05), helios::make_vec3(1, 1, 1), "positive");
1955 updatePrimitiveTypes();
1956
1957 // Setup Dear ImGui context
1958 IMGUI_CHECKVERSION();
1959 ImGui::CreateContext();
1960 ImGuiIO &io = ImGui::GetIO();
1961 // ImFont* font_awesome = io.Fonts->AddFontFromFileTTF("plugins/visualizer/fonts/FontAwesome.ttf", 16.0f);
1962 ImFont *arial = io.Fonts->AddFontFromFileTTF("plugins/visualizer/fonts/Arial.ttf", 16.0f);
1963 io.Fonts->Build();
1964 // ImGui::PushFont(arial);
1965 io.FontDefault = arial;
1966 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
1967
1968 // void* window;
1969
1970 // glfwShowWindow((GLFWwindow *) window);
1971
1972 // GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", nullptr, nullptr);
1973 GLFWwindow *window = (GLFWwindow *) visualizer->getWindow();
1974 glfwShowWindow(window);
1975
1976 bool show_demo_window = false;
1977 bool my_tool_active = true;
1978 // bool user_input = false;
1979
1980 // Setup Platform/Renderer backends
1981 ImGui_ImplGlfw_InitForOpenGL(window, true);
1982 ImGui_ImplOpenGL3_Init();
1983 // glfwSwapInterval(1); // enable V-Sync
1984
1985 ImVec2 current_position;
1986 ImVec2 last_position;
1987 bool currently_collapsed;
1988 bool previously_collapsed = false;
1989 std::string current_tab = "General";
1990 std::string previous_tab = "General";
1991
1992 // (Your code calls glfwPollEvents())
1993 // ...
1994 // Start the Dear ImGui frame
1995
1996 bool switch_visualization = false;
1997
1998 std::string current_cam_position = "0";
1999 while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose((GLFWwindow *) window) == 0) {
2000 glfwPollEvents();
2001 ImGui_ImplOpenGL3_NewFrame();
2002 ImGui_ImplGlfw_NewFrame();
2003 ImGui::NewFrame();
2004 // ImGui::ShowDemoWindow(&show_demo_window); // Show demo window! :)
2005
2006 // glfwSetKeyCallback(window, key_callback);
2007
2008 // Check for key press or mouse movement
2009 // if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS ||
2010 // glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
2011 // user_input = true;
2012 // }
2013
2014 // if (ImGui::IsKeyDown(ImGuiKey_Q)) {
2015 // user_input = true;
2016 // }
2017 //
2018 // if (user_input)
2019 // visualizer->plotUpdate();
2020
2021 user_input = false;
2022 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize;
2023 ImGuiWindowFlags window_flags2 = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize;
2024
2025 // ImGui::SetNextWindowSize(ImVec2(500, 400));
2026 // ImVec2 windowSize = ImGui::GetWindowSize();
2027 int windowSize_x = 0;
2028 int windowSize_y = 0;
2029 // visualizer->getWindowSize(windowSize_x, windowSize_y);
2030 glfwGetWindowSize((GLFWwindow *) window, &windowSize_x, &windowSize_y);
2031 int2 windowSize(windowSize_x, windowSize_y);
2032 // TEST
2033 glm::mat4 perspectiveTransformationMatrix = visualizer->getPerspectiveTransformationMatrix();
2034 glm::vec4 origin_position;
2035 std::string current_label;
2036 if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
2037 currently_dragging = "";
2038 disable_dragging = true;
2039 }
2040 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
2041 if (!currently_dragging.empty()) {
2042 // ImVec2 mouse_pos = ImGui::GetMousePos();
2043 // float ndcX = (2.0f * mouse_pos.x / windowSize.x) - 1.0f;
2044 // float ndcY = 1.0f - (2.0f * mouse_pos.y / windowSize.y);
2045 // std::vector<vec3> camera_lookat_pos = visualizer->getCameraPosition();
2046 // vec3 camera_pos = camera_lookat_pos[0];
2047 // vec3 lookat_pos = camera_lookat_pos[1];
2048 // float depth = (camera_pos - lookat_pos).magnitude();
2049 // glm::vec4 clip_pos(ndcX, ndcY, depth, 1.0f);
2050 // glm::vec4 view_pos = glm::inverse(perspectiveTransformationMatrix) * clip_pos;
2051 // view_pos /= view_pos.w;
2052 // glm::mat4 viewMatrix = visualizer->getViewMatrix();
2053 // glm::vec4 world_pos = glm::inverse(viewMatrix) * view_pos;
2054 // glm::vec3 final_pos = glm::vec3(world_pos.x, world_pos.y, world_pos.z);
2055 ImVec2 mouse_pos = ImGui::GetMousePos();
2056 std::vector<vec3> camera_lookat_pos = visualizer->getCameraPosition();
2057 vec3 camera_pos = camera_lookat_pos[0];
2058 vec3 lookat_pos = camera_lookat_pos[1];
2059 float drag_distance = std::sqrt(std::pow(mouse_pos.x - dragging_start_position.x, 2) + std::pow(mouse_pos.y - dragging_start_position.y, 2));
2060 ;
2061 float depth = (camera_pos - lookat_pos).magnitude();
2062 vec3 view_dir = (camera_pos - lookat_pos).normalize();
2063
2064 vec3 world_up = vec3(0, 1, 0);
2065
2066 vec3 right_dir = cross(world_up, view_dir);
2067 right_dir = right_dir.normalize();
2068
2069 vec3 up_dir = cross(view_dir, right_dir).normalize();
2070
2071 right_dir = cross(view_dir, world_up).normalize();
2072 float base_offset = 0.001f;
2073 float offset = base_offset * depth;
2074
2075 if (currently_dragging_type == "canopy") {
2076 canopy_dict[currently_dragging].origin += drag_distance * offset * (up_dir + right_dir);
2077 } else if (currently_dragging_type == "rig") {
2078 camera_positions[rig_dict[currently_dragging]] += drag_distance * offset * (up_dir + right_dir);
2079 }
2080 }
2081 currently_dragging = "";
2082 disable_dragging = false;
2083 dragging_start_position = int2(0, 0);
2084 }
2085 int object_window_count = 0;
2086 for (auto current_label: canopy_labels_set) {
2087 vec3 canopy_origin_ = canopy_dict[current_label].origin;
2088 origin_position = glm::vec4(canopy_origin_.x, canopy_origin_.y, canopy_origin_.z, 1.0);
2089 origin_position = perspectiveTransformationMatrix * origin_position;
2090 // ImGui::SetNextWindowSize(ImVec2(150, 10), ImGuiCond_Always);
2091 // ImGui::SetNextWindowSize(ImVec2(150, 10));
2092 ImVec2 next_window_pos = ImVec2(((origin_position.x / origin_position.w) * 0.5f + 0.5f) * windowSize.x, (1.0f - ((origin_position.y / origin_position.w) * 0.5f + 0.5f)) * windowSize.y);
2093 // WINDOW MOUSE CLICK AND DRAG
2094 // TODO: re-enable this feature when it is improved
2095 // ImVec2 mouse_pos = ImGui::GetMousePos();
2096 // bool drag_window = (mouse_pos.x >= next_window_pos.x && mouse_pos.x <= next_window_pos.x + 150 &&
2097 // mouse_pos.y >= next_window_pos.y && mouse_pos.y <= next_window_pos.y + 10);
2098 // if (drag_window && ImGui::IsMouseDown(ImGuiMouseButton_Left) && currently_dragging.empty() && !disable_dragging){
2099 // currently_dragging = current_label;
2100 // currently_dragging_type = "canopy";
2101 // dragging_start_position = int2(mouse_pos.x, mouse_pos.y);
2102 // }
2103 // if (!disable_dragging && currently_dragging == current_label){
2104 // ImGui::SetNextWindowPos(mouse_pos);
2105 // } else{
2106 ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
2107 ImGui::SetNextWindowPos(next_window_pos);
2108 // }
2109 ImGui::Begin((current_label + "###" + std::to_string(object_window_count)).c_str(), nullptr, //&my_tool_active,
2110 ImGui::IsWindowCollapsed() ? 0 : ImGuiWindowFlags_AlwaysAutoResize);
2111 if (ImGui::IsWindowCollapsed()) {
2112 ImGui::SetWindowSize(ImVec2(150, 10));
2113 }
2114 canopyTab(current_label, object_window_count);
2115 ImGui::End();
2116 object_window_count++;
2117 }
2118 for (auto current_label: rig_labels_set) {
2119 vec3 camera_position_ = camera_position_vec[rig_dict[current_label]][0];
2120 origin_position = glm::vec4(camera_position_.x, camera_position_.y, camera_position_.z, 1.0);
2121 origin_position = perspectiveTransformationMatrix * origin_position;
2122 // ImGui::SetNextWindowSize(ImVec2(150, 10), ImGuiCond_Always);
2123 // ImGui::SetNextWindowSize(ImVec2(150, 10));
2124 ImVec2 next_window_pos = ImVec2(((origin_position.x / origin_position.w) * 0.5f + 0.5f) * windowSize.x, (1.0f - ((origin_position.y / origin_position.w) * 0.5f + 0.5f)) * windowSize.y);
2125 // WINDOW MOUSE CLICK AND DRAG
2126 // TODO: re-enable this feature when it is improved
2127 // ImVec2 mouse_pos = ImGui::GetMousePos();
2128 // bool drag_window = (mouse_pos.x >= next_window_pos.x && mouse_pos.x <= next_window_pos.x + 150 &&
2129 // mouse_pos.y >= next_window_pos.y && mouse_pos.y <= next_window_pos.y + 10);
2130 // if (drag_window && ImGui::IsMouseDown(ImGuiMouseButton_Left) && currently_dragging.empty() && !disable_dragging){
2131 // currently_dragging = current_label;
2132 // currently_dragging_type = "rig";
2133 // dragging_start_position = int2(mouse_pos.x, mouse_pos.y);
2134 // }
2135 // if (!disable_dragging && currently_dragging == current_label){
2136 // ImGui::SetNextWindowPos(mouse_pos);
2137 // } else{
2138 ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
2139 ImGui::SetNextWindowPos(next_window_pos);
2140 // }
2141 ImGui::Begin((current_label + "###" + std::to_string(object_window_count)).c_str(), nullptr, // &my_tool_active,
2142 ImGui::IsWindowCollapsed() ? 0 : ImGuiWindowFlags_AlwaysAutoResize);
2143 if (ImGui::IsWindowCollapsed()) {
2144 ImGui::SetWindowSize(ImVec2(150, 10));
2145 }
2146 rigTab(current_label, object_window_count);
2147 ImGui::End();
2148 object_window_count++;
2149 }
2150 for (std::string obj_name: obj_names_set) {
2151 current_label = obj_name;
2152 vec3 obj_position_ = objects_dict[current_label].position;
2153 origin_position = glm::vec4(obj_position_.x, obj_position_.y, obj_position_.z, 1.0);
2154 origin_position = perspectiveTransformationMatrix * origin_position;
2155 // ImGui::SetNextWindowSize(ImVec2(150, 10), ImGuiCond_Always);
2156 // ImGui::SetNextWindowSize(ImVec2(150, 10));
2157 ImVec2 next_window_pos = ImVec2(((origin_position.x / origin_position.w) * 0.5f + 0.5f) * windowSize.x, (1.0f - ((origin_position.y / origin_position.w) * 0.5f + 0.5f)) * windowSize.y);
2158 // WINDOW MOUSE CLICK AND DRAG
2159 // TODO: re-enable this feature when it is improved
2160 // ImVec2 mouse_pos = ImGui::GetMousePos();
2161 // bool drag_window = (mouse_pos.x >= next_window_pos.x && mouse_pos.x <= next_window_pos.x + 150 &&
2162 // mouse_pos.y >= next_window_pos.y && mouse_pos.y <= next_window_pos.y + 10);
2163 // if (drag_window && ImGui::IsMouseDown(ImGuiMouseButton_Left) && currently_dragging.empty() && !disable_dragging){
2164 // currently_dragging = current_label;
2165 // currently_dragging_type = "object";
2166 // dragging_start_position = int2(mouse_pos.x, mouse_pos.y);
2167 // }
2168 // if (!disable_dragging && currently_dragging == current_label){
2169 // ImGui::SetNextWindowPos(mouse_pos);
2170 // } else{
2171 ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
2172 ImGui::SetNextWindowPos(next_window_pos);
2173 // }
2174 ImGui::Begin((current_label + "###" + std::to_string(object_window_count)).c_str(), nullptr, // &my_tool_active,
2175 ImGui::IsWindowCollapsed() ? 0 : ImGuiWindowFlags_AlwaysAutoResize);
2176 if (ImGui::IsWindowCollapsed()) {
2177 ImGui::SetWindowSize(ImVec2(150, 10));
2178 }
2179 objectTab(current_label, object_window_count);
2180 ImGui::End();
2181 object_window_count++;
2182 }
2183 //
2184 ImGui::SetNextWindowCollapsed(false, ImGuiCond_Once);
2185 ImGui::Begin("Editor", nullptr, window_flags2); // Begin editor window
2186 // ImGui::SetNextWindowPos(ImVec2(windowSize.x - 400.0f, 0), ImGuiCond_Always); // flag -> can't move window with mouse
2187 // ImGui::SetNextWindowPos(ImVec2(windowSize.x - 400.0f, 0), ImGuiCond_Always);
2188 current_position = ImGui::GetWindowPos();
2189 currently_collapsed = ImGui::IsWindowCollapsed();
2190
2191 if (current_tab != previous_tab || current_position.x != last_position.x || current_position.y != last_position.y || currently_collapsed != previously_collapsed) {
2192 user_input = true;
2193 previous_tab = current_tab;
2194 }
2195 if (ImGui::BeginMenuBar()) {
2196 if (ImGui::BeginMenu("File")) {
2197 if (ImGui::MenuItem("Open..", "Ctrl+O")) {
2198 std::string file_name = file_dialog();
2199 if (!file_name.empty()) {
2200 xmlGetValues(file_name);
2201 }
2202 }
2203 if (ImGui::MenuItem("Save XML", "Ctrl+S")) {
2204 xmlSetValues();
2205 }
2206 if (ImGui::MenuItem("Save As", "Ctrl+S")) {
2207 std::string new_xml_file = save_as_file_dialog(std::vector<std::string>{"XML"});
2208 if (!new_xml_file.empty()) {
2209 std::string file_extension = new_xml_file;
2210 size_t last_obj_file = file_extension.rfind('.');
2211 if (last_obj_file != std::string::npos) {
2212 file_extension = file_extension.substr(last_obj_file + 1);
2213 }
2214 if (file_extension == "xml") {
2215 if (!std::filesystem::exists(new_xml_file)) {
2216 // Create file
2217 std::filesystem::copy(xml_input_file, new_xml_file, std::filesystem::copy_options::overwrite_existing);
2218 }
2219 // Change XML input file
2220 std::string xml_input_file_ = xml_input_file;
2221 pugi::xml_node helios_ = helios;
2222 xml_input_file = new_xml_file;
2223 if (!open_xml_file(xml_input_file, xmldoc, xml_error_string)) {
2224 helios_runtime_error(xml_error_string);
2225 }
2226 xmlSetValues();
2227 // Change XML input file back to original
2228 // xml_input_file = xml_input_file_;
2229 // helios = helios_;
2230 // if( !open_xml_file(xml_input_file, xmldoc, xml_error_string) ) {
2231 // helios_runtime_error(xml_error_string);
2232 // }
2233 } else {
2234 // Needs to be a obj or ply file
2235 std::cout << "Not a valid file type. Project must be saved to a XML file." << std::endl;
2236 }
2237 } else {
2238 // Not a valid file
2239 std::cout << "Not a valid file." << std::endl;
2240 }
2241 }
2242 if (ImGui::MenuItem("Close", "Ctrl+W")) {
2243 my_tool_active = false;
2244 }
2245 ImGui::EndMenu();
2246 }
2247 if (ImGui::BeginMenu("Visualization")) {
2248 refreshVisualizationTypes();
2249 refreshVisualizationTypes();
2250 if (ImGui::MenuItem("RGB (Default)") && visualization_type != "RGB") {
2251 visualization_type = "RGB";
2252 switch_visualization = true;
2253 }
2254 std::set<std::string> vis_types;
2255 std::set_union(visualization_types_primitive.begin(), visualization_types_primitive.end(), visualization_types_object.begin(), visualization_types_object.end(), std::inserter(vis_types, vis_types.begin()));
2256 for (auto &type: vis_types) {
2257 if (visualization_types_primitive.find(type) != visualization_types_primitive.end()) {
2258 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 165, 0, 255)); // orange text
2259 } else {
2260 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 0, 255, 255)); // blue text
2261 }
2262 if (ImGui::MenuItem(type.c_str()) && visualization_type != type) {
2263 visualization_type = type;
2264 switch_visualization = true;
2265 }
2266 ImGui::PopStyleColor();
2267 }
2268 if (switch_visualization) {
2269 if (visualization_type != "RGB") {
2270 if (visualization_types_primitive.find(visualization_type) != visualization_types_primitive.end()) {
2271 visualizer->colorContextPrimitivesByData(visualization_type.c_str());
2272 } else {
2273 visualizer->colorContextPrimitivesByObjectData(visualization_type.c_str());
2274 }
2275 } else {
2277 }
2278 is_dirty = true;
2279 switch_visualization = false;
2280 }
2281 ImGui::EndMenu();
2282 }
2283 ImGui::EndMenuBar();
2284 }
2285 std::string image_dir = "./saved/";
2286 bool dir = std::filesystem::create_directories(image_dir);
2287 if (!dir && !std::filesystem::exists(image_dir)) {
2288 helios_runtime_error("Error: image output directory " + image_dir + " could not be created. Exiting...");
2289 }
2290// context.setPrimitiveData(UUIDs_bunny, "bunny", uint(0));
2291// plant segmentation bounding boxes
2292// plant ID bounding boxes (plant architecture->optional plant output data)
2293#ifdef ENABLE_RADIATION_MODEL
2294 if (ImGui::Button("Record")) {
2295 if (band_group_names.empty()) {
2296 std::cout << "At least 1 band group (a group of 1 or 3 bands) must be defined to record images." << std::endl;
2297 } else {
2298 // Update reflectivity, transmissivity, & emissivity for each band / primitive_type
2299 const char *font_name = "LCD";
2300 visualizer->addTextboxByCenter("LOADING...", vec3(.5, .5, 0), make_SphericalCoord(0, 0), RGB::red, 40, font_name, Visualizer::COORDINATES_WINDOW_NORMALIZED);
2302 updatePrimitiveTypes();
2303 updateSpectra();
2304 updateCameras(); // TODO: figure out why this causes an error
2305 try {
2306 record();
2307 } catch (const std::runtime_error &e) {
2308 std::cerr << "Record failed due to exception: " << e.what() << std::endl;
2310 }
2311 }
2312 }
2313 recordPopup();
2314 ImGui::OpenPopupOnItemClick("repeat_record", ImGuiPopupFlags_MouseButtonRight);
2315#endif // RADIATION_MODEL
2316 // ####### RESULTS ####### //
2317 // ImGui::Text("Absorbed PAR: %f W/m^2", PAR_absorbed);
2318 // ImGui::Text("Absorbed NIR: %f W/m^2", NIR_absorbed);
2319 // ImGui::Text("Absorbed LW: %f W/m^2", LW_absorbed);
2320 ImGui::Text("Console:");
2321 outputConsole();
2322 if (ImGui::BeginTabBar("Settings#left_tabs_bar")) {
2323 if (ImGui::BeginTabItem("General")) {
2324 current_tab = "General";
2325 generalTab();
2326
2327 ImGui::EndTabItem();
2328 }
2329 // Calculation Tab
2330 if (ImGui::BeginTabItem("Calculation")) {
2331 current_tab = "Calculation";
2332 calculationTab();
2333
2334 ImGui::EndTabItem();
2335 }
2336 // OBJECT TAB
2337 if (ImGui::BeginTabItem("Object")) {
2338 current_tab = "Object";
2339 objectTab();
2340 ImGui::EndTabItem();
2341 }
2342 // CANOPY TAB
2343 if (ImGui::BeginTabItem("Canopy")) {
2344 current_tab = "Canopy";
2345 canopyTab();
2346
2347 ImGui::EndTabItem();
2348 }
2349 if (enable_radiation) {
2350 if (ImGui::BeginTabItem("Radiation")) {
2351 current_tab = "Radiation";
2352 radiationTab();
2353
2354 ImGui::EndTabItem();
2355 }
2356 }
2357 if (enable_radiation) {
2358 // RIG TAB
2359 if (ImGui::BeginTabItem("Rig")) {
2360 current_tab = "Rig";
2361 rigTab();
2362
2363 ImGui::EndTabItem();
2364 }
2365 // CAMERA TAB
2366 if (ImGui::BeginTabItem("Camera")) {
2367 current_tab = "Camera";
2368 cameraTab();
2369
2370 ImGui::EndTabItem();
2371 }
2372 // LIGHT TAB
2373 if (ImGui::BeginTabItem("Light")) {
2374 current_tab = "Light";
2375 lightTab();
2376
2377 ImGui::EndTabItem();
2378 }
2379 }
2380 ImGui::EndTabBar();
2381 }
2382 last_position = current_position;
2383 previously_collapsed = currently_collapsed;
2384 ImGui::End();
2385
2386 if (is_dirty && !ImGui::IsMouseDragging(ImGuiMouseButton_Left) && !ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
2388 // TODO: requery primitive types here
2389 // updatePrimitiveTypes();
2390 // refreshVisualizationTypes();
2391 updatePrimitiveTypes();
2393 is_dirty = false;
2394 }
2395
2396 // Rendering
2397 // (Your code clears your framebuffer, renders your other stuff etc.)
2398 // glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Set a background color (e.g., dark grey)
2399 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2400 visualizer->plotOnce(!io.WantCaptureMouse);
2401 ImGui::Render();
2402
2403 ImDrawData *draw_data = ImGui::GetDrawData();
2404
2405 ImGui_ImplOpenGL3_RenderDrawData(draw_data);
2406 glfwSwapBuffers(window);
2407 if (!io.WantCaptureMouse && !ImGui::IsAnyItemHovered()) {
2408 glfwWaitEvents();
2409 }
2410 // (Your code calls glfwSwapBuffers() etc.)
2411
2412 std::this_thread::sleep_for(std::chrono::milliseconds(100 / 6));
2413 }
2414
2415 ImGui_ImplOpenGL3_Shutdown();
2416 ImGui_ImplGlfw_Shutdown();
2417 ImGui::DestroyContext();
2418// }else{
2419#else
2420 std::cout << "Visualizer plugin is required for this function." << std::endl;
2421// } //HELIOS_VISUALIZER
2422#endif // HELIOS_VISUALIZER
2423}
2424
2425
2426void ProjectBuilder::buildAndVisualize(std::string xml_path) {
2427 buildFromXML(xml_path);
2428 visualize();
2429}
2430
2431
2436
2437
2439 // MAIN BLOCK
2440 // *** Latitude *** //
2441 xmlSetValue("latitude", "helios", latitude);
2442 xmlSetDistribution("latitude_dist", "helios", distributions[distribution_dict["latitude"]]);
2443 // *** Longitude *** //
2444 xmlSetValue("longitude", "helios", longitude);
2445 xmlSetDistribution("longitude_dist", "helios", distributions[distribution_dict["longitude"]]);
2446 // *** UTC Offset *** //
2447 xmlSetValue("UTC_offset", "helios", UTC_offset);
2448 xmlSetDistribution("UTC_offset_dist", "helios", distributions[distribution_dict["UTC_offset"]]);
2449 // *** CSV Weather File *** //
2450 xmlSetValue("csv_weather_file", "helios", csv_weather_file);
2451 // *** Domain Origin *** //
2452 xmlSetValue("domain_origin", "helios", domain_origin);
2453 xmlSetDistribution("domain_origin_x_dist", "helios", distributions[distribution_dict["domain_origin_x"]]);
2454 xmlSetDistribution("domain_origin_y_dist", "helios", distributions[distribution_dict["domain_origin_y"]]);
2455 xmlSetDistribution("domain_origin_z_dist", "helios", distributions[distribution_dict["domain_origin_z"]]);
2456 // *** Domain Extent *** //
2457 xmlSetValue("domain_extent", "helios", domain_extent);
2458 xmlSetDistribution("domain_extent_x_dist", "helios", distributions[distribution_dict["domain_extent_x"]]);
2459 xmlSetDistribution("domain_extent_y_dist", "helios", distributions[distribution_dict["domain_extent_y"]]);
2460 // *** Ground Resolution *** //
2461 xmlSetValue("ground_resolution", "helios", ground_resolution);
2462 xmlSetDistribution("ground_resolution_x_dist", "helios", distributions[distribution_dict["ground_resolution_x"]]);
2463 xmlSetDistribution("ground_resolution_y_dist", "helios", distributions[distribution_dict["ground_resolution_y"]]);
2464 // *** Ground Texture File *** //
2465 xmlSetValue("ground_texture_file", "helios", ground_texture_file);
2466 // *** Camera XML Library File *** //
2467 xmlSetValues("camera_xml_library_file", "helios", camera_xml_library_files);
2468 // *** Light XML Library File *** //
2469 xmlSetValues("light_xml_library_file", "helios", light_xml_library_files);
2470 // OBJECT BLOCK
2471 // Delete from XML doc
2472 helios = xmldoc.child("helios");
2473 pugi::xml_node node;
2474 node = helios.child("object");
2475 if (node) {
2476 node.parent().remove_child(node);
2477 }
2478 // Refresh lists
2479 obj_names.clear();
2480 obj_files.clear();
2481 obj_positions.clear();
2482 obj_orientations.clear();
2483 obj_scales.clear();
2484 obj_colors.clear();
2485 obj_data_groups.clear();
2486 for (std::string obj_name: obj_names_set) {
2487 object curr_obj = objects_dict[obj_name];
2488 obj_names.push_back(curr_obj.name);
2489 obj_files.push_back(curr_obj.file);
2490 obj_positions.push_back(curr_obj.position);
2491 obj_orientations.push_back(curr_obj.orientation);
2492 obj_scales.push_back(curr_obj.scale);
2493 obj_colors.push_back(curr_obj.color);
2494 obj_data_groups.push_back(curr_obj.data_group);
2495 }
2496 //
2497 setNodeLabels("label", "object", obj_names_set);
2498 xmlSetValues("file", "object", obj_files, obj_names_dict);
2499 xmlSetValues("position", "object", obj_positions, obj_names_dict);
2500 xmlSetValues("orientation", "object", obj_orientations, obj_names_dict);
2501 xmlSetValues("scale", "object", obj_scales, obj_names_dict);
2502 xmlSetValues("color", "object", obj_colors, obj_names_dict);
2503 xmlSetValues("data_group", "object", obj_data_groups, obj_names_dict);
2504// CANOPY BLOCK
2505#ifdef ENABLE_PLANT_ARCHITECTURE
2506 // Delete from XML doc
2507 helios = xmldoc.child("helios");
2508 node = helios.child("canopy");
2509 if (node) {
2510 node.parent().remove_child(node);
2511 }
2512 // Refresh lists
2513 plant_ages.clear();
2514 ground_clipping_heights.clear();
2515 canopy_labels.clear();
2516 plant_library_names.clear();
2517 plant_library_names_verbose.clear();
2518 canopy_IDs.clear();
2519 individual_plant_locations.clear();
2520 plant_spacings.clear();
2521 plant_counts.clear();
2522 canopy_origins.clear();
2523 canopy_data_groups.clear();
2524 for (std::string canopy_name: canopy_labels_set) {
2525 canopy curr_canopy = canopy_dict[canopy_name];
2526 plant_ages.push_back(curr_canopy.age);
2527 ground_clipping_heights.push_back(curr_canopy.ground_clipping_height);
2528 canopy_labels.push_back(curr_canopy.label);
2529 plant_library_names.push_back(curr_canopy.library_name);
2530 plant_library_names_verbose.push_back(curr_canopy.library_name_verbose);
2531 canopy_IDs.push_back(curr_canopy.IDs);
2532 individual_plant_locations.push_back(curr_canopy.individual_plant_locations);
2533 plant_spacings.push_back(curr_canopy.plant_spacing);
2534 plant_counts.push_back(curr_canopy.plant_count);
2535 canopy_origins.push_back(curr_canopy.origin);
2536 canopy_data_groups.push_back(curr_canopy.data_group);
2537 }
2538 //
2539 setNodeLabels("label", "canopy_block", canopy_labels_set);
2540 xmlSetValue("canopy_origin", "canopy_block", canopy_origin);
2541 xmlSetValue("plant_count", "canopy_block", plant_count);
2542 xmlSetValue("plant_spacing", "canopy_block", plant_spacing);
2543 xmlSetValue("plant_library_name", "canopy_block", plant_library_name);
2544 xmlSetValue("plant_age", "canopy_block", plant_age);
2545 xmlSetValue("ground_clipping_height", "canopy_block", ground_clipping_height);
2546 xmlSetValues("canopy_origin", "canopy_block", canopy_origins, canopy_labels_dict);
2547 xmlSetValues("plant_count", "canopy_block", plant_counts, canopy_labels_dict);
2548 xmlSetValues("plant_spacing", "canopy_block", plant_spacings, canopy_labels_dict);
2549 xmlSetValues("plant_library_name", "canopy_block", plant_library_names, canopy_labels_dict);
2550 xmlSetValues("plant_age", "canopy_block", plant_ages, canopy_labels_dict);
2551 xmlSetValues("ground_clipping_height", "canopy_block", ground_clipping_heights, canopy_labels_dict);
2552 xmlSetValues("data_group", "canopy_block", canopy_data_groups, canopy_labels_dict);
2553#endif
2554 // RIG BLOCK
2555 // Delete from XML doc
2556 helios = xmldoc.child("helios");
2557 node = helios.child("rig");
2558 if (node) {
2559 node.parent().remove_child(node);
2560 }
2561 setNodeLabels("label", "rig", rig_labels_set);
2562 xmlSetValues("color", "rig", rig_colors, rig_dict);
2563 // xmlSetValue("camera_position", "rig", camera_position);
2564 // xmlSetValue("camera_lookat", "rig", camera_lookat);
2565 xmlSetValue("camera_label", "rig", camera_label);
2566 // xmlSetValues("camera_position", "rig", camera_positions);
2567 xmlSetValues("camera_position", "rig", camera_position_vec, rig_dict);
2568 // xmlSetValues("camera_lookat", "rig", camera_lookats);
2569 xmlSetValues("camera_lookat", "rig", camera_lookat_vec, rig_dict);
2570 // xmlSetValues("camera_label", "rig", camera_labels);
2571 xmlSetValues("camera_label", "rig", rig_camera_labels, rig_dict);
2572 setKeypoints("keypoint", "camera_position", keypoint_frames);
2573 xmlSetValues("images", "rig", num_images_vec, rig_dict);
2574 std::vector<int> write_depth_{};
2575 std::vector<int> write_norm_depth_{};
2576 for (int i = 0; i < write_depth.size(); i++) {
2577 if (write_depth[i]) {
2578 write_depth_.push_back(1);
2579 } else {
2580 write_depth_.push_back(0);
2581 }
2582 if (write_norm_depth[i]) {
2583 write_norm_depth_.push_back(1);
2584 } else {
2585 write_norm_depth_.push_back(0);
2586 }
2587 }
2588 xmlSetValues("depth", "rig", write_depth_, rig_dict);
2589 xmlSetValues("normdepth", "rig", write_norm_depth_, rig_dict);
2590 // CAMERA BLOCK
2591 setNodeLabels("label", "camera", camera_names_set);
2592 xmlSetValue("camera_resolution", "camera", camera_resolution);
2593 xmlSetValue("focal_plane_distance", "camera", focal_plane_distance);
2594 xmlSetValue("lens_diameter", "camera", lens_diameter);
2595 xmlSetValue("FOV_aspect_ratio", "camera", FOV_aspect_ratio);
2596 xmlSetValue("HFOV", "camera", HFOV);
2597 xmlSetValues("camera_resolution", "camera", camera_resolutions, camera_dict);
2598 for (std::string &band: bandlabels) {
2599 for (std::string &camera: camera_names) {
2600 xmlSetValue("camera_calibration_" + band, "camera", camera_calibrations[camera_dict[camera]][band]);
2601 }
2602 }
2603 xmlSetValues("focal_plane_distance", "camera", focal_plane_distances, camera_dict);
2604 xmlSetValues("lens_diameter", "camera", lens_diameters, camera_dict);
2605 xmlSetValues("FOV_aspect_ratio", "camera", FOV_aspect_ratios, camera_dict);
2606 xmlSetValues("HFOV", "camera", HFOVs, camera_dict);
2607 // LIGHT BLOCK
2608 setNodeLabels("label", "light", light_names_set);
2609 xmlSetValues("light_type", "light", light_types, light_dict);
2610 xmlSetValues("light_spectra", "light", light_spectra, light_dict);
2611 xmlSetValues("light_direction", "light", light_direction_vec, light_dict);
2612 xmlSetValues("light_rotation", "light", light_rotation_vec, light_dict);
2613 xmlSetValues("light_size", "light", light_size_vec, light_dict);
2614 xmlSetValues("light_source_flux", "light", light_flux_vec, light_dict);
2615 xmlSetValues("light_radius", "light", light_radius_vec, light_dict);
2616 xmlSetValues("light_label", "rig", rig_light_labels, light_dict);
2617 // RADIATION BLOCK
2618 xmlSetValue("direct_ray_count", "radiation", direct_ray_count);
2619 xmlSetValue("diffuse_ray_count", "radiation", diffuse_ray_count);
2620 xmlSetValue("diffuse_extinction_coeff", "radiation", diffuse_extinction_coeff);
2621 xmlSetValue("scattering_depth", "radiation", scattering_depth);
2622 xmlSetValue("air_turbidity", "radiation", air_turbidity);
2623 xmlSetValues("load_xml_library_file", "radiation", xml_library_files);
2624 xmlSetValue("solar_direct_spectrum", "radiation", solar_direct_spectrum);
2625 xmlSetValue("leaf_reflectivity_spectrum", "radiation", leaf_reflectivity_spectrum);
2626 xmlSetValue("leaf_transmissivity_spectrum", "radiation", leaf_transmissivity_spectrum);
2627 xmlSetValue("leaf_emissivity", "radiation", leaf_emissivity);
2628 xmlSetValue("ground_reflectivity_spectrum", "radiation", ground_reflectivity_spectrum);
2629 for (std::string prim: primitive_names) {
2630 if (prim == "All")
2631 continue;
2632 // Reflectivity
2633 if (primitive_continuous[prim][0]) {
2634 xmlSetValue(prim + "_reflectivity_spectrum", "radiation", primitive_spectra[prim][0]);
2635 } else {
2636 xmlRemoveField(prim + "_reflectivity_spectrum", "radiation");
2637 }
2638 // Transmissivity
2639 if (primitive_continuous[prim][1]) {
2640 xmlSetValue(prim + "_transmissivity_spectrum", "radiation", primitive_spectra[prim][1]);
2641 } else {
2642 xmlRemoveField(prim + "_transmissivity_spectrum", "radiation");
2643 }
2644 for (std::string band: bandlabels) {
2645 if (band == "All")
2646 continue;
2647 xmlSetValue(prim + "_reflectivity", "radiation", primitive_values[band][prim][0]);
2648 xmlSetValue(prim + "_transmissivity", "radiation", primitive_values[band][prim][1]);
2649 xmlSetValue(prim + "_emissivity", "radiation", primitive_values[band][prim][2]);
2650 }
2651 }
2652 xmldoc.save_file(xml_input_file.c_str());
2653}
2654
2655
2656void ProjectBuilder::xmlSetValues(std::string xml_path) {
2657 xml_input_file = xml_path;
2658 if (!open_xml_file(xml_input_file, xmldoc, xml_error_string)) {
2659 helios_runtime_error(xml_error_string);
2660 }
2661 xmlSetValues();
2662}
2663
2664
2666 distribution curr_distribution = distribution{};
2667 // MAIN BLOCK
2668 // *** Latitude *** //
2669 xmlGetValue("latitude", "helios", latitude);
2670 curr_distribution = distribution{};
2671 xmlGetDistribution("latitude_dist", "helios", curr_distribution);
2672 applyDistribution("latitude", curr_distribution, createTaggedPtr(&latitude));
2673 // *** Longitude *** //
2674 xmlGetValue("longitude", "helios", longitude);
2675 curr_distribution = distribution{};
2676 xmlGetDistribution("longitude_dist", "helios", curr_distribution);
2677 applyDistribution("longitude", curr_distribution, createTaggedPtr(&longitude));
2678 // *** UTC Offset *** //
2679 xmlGetValue("UTC_offset", "helios", UTC_offset);
2680 curr_distribution = distribution{};
2681 xmlGetDistribution("UTC_offset_dist", "helios", curr_distribution);
2682 applyDistribution("UTC_offset", curr_distribution, createTaggedPtr(&UTC_offset));
2683 // *** CSV Weather File *** //
2684 xmlGetValue("csv_weather_file", "helios", csv_weather_file);
2685 // *** Domain Origin *** //
2686 xmlGetValue("domain_origin", "helios", domain_origin);
2687 curr_distribution = distribution{};
2688 xmlGetDistribution("domain_origin_x_dist", "helios", curr_distribution);
2689 applyDistribution("domain_origin_x", curr_distribution, createTaggedPtr(&domain_origin.x));
2690 curr_distribution = distribution{};
2691 xmlGetDistribution("domain_origin_y_dist", "helios", curr_distribution);
2692 applyDistribution("domain_origin_y", curr_distribution, createTaggedPtr(&domain_origin.y));
2693 curr_distribution = distribution{};
2694 xmlGetDistribution("domain_origin_z_dist", "helios", curr_distribution);
2695 applyDistribution("domain_origin_z", curr_distribution, createTaggedPtr(&domain_origin.z));
2696 // *** Domain Extent *** //
2697 xmlGetValue("domain_extent", "helios", domain_extent);
2698 curr_distribution = distribution{};
2699 xmlGetDistribution("domain_extent_x_dist", "helios", curr_distribution);
2700 applyDistribution("domain_extent_x", curr_distribution, createTaggedPtr(&domain_extent.x));
2701 curr_distribution = distribution{};
2702 xmlGetDistribution("domain_extent_y_dist", "helios", curr_distribution);
2703 applyDistribution("domain_extent_y", curr_distribution, createTaggedPtr(&domain_extent.y));
2704 // *** Ground Resolution *** //
2705 xmlGetValue("ground_resolution", "helios", ground_resolution);
2706 curr_distribution = distribution{};
2707 xmlGetDistribution("ground_resolution_x_dist", "helios", curr_distribution);
2708 applyDistribution("ground_resolution_x", curr_distribution, createTaggedPtr(&ground_resolution.x));
2709 curr_distribution = distribution{};
2710 xmlGetDistribution("ground_resolution_y_dist", "helios", curr_distribution);
2711 applyDistribution("ground_resolution_y", curr_distribution, createTaggedPtr(&ground_resolution.y));
2712 // *** Ground Texture File *** //
2713 xmlGetValue("ground_texture_file", "helios", ground_texture_file);
2714 // *** Camera XML Library Files *** //
2715 xmlGetValues("camera_xml_library_file", "helios", camera_xml_library_files);
2716 possible_camera_calibrations.clear();
2717 for (auto &xml_library_file: camera_xml_library_files) {
2718 if (xml_library_file.empty() || !std::filesystem::exists(xml_library_file)) {
2719 continue;
2720 }
2721 std::vector<std::string> current_camera_file = get_xml_node_values(xml_library_file, "label", "globaldata_vec2");
2722 possible_camera_calibrations.insert(possible_camera_calibrations.end(), current_camera_file.begin(), current_camera_file.end());
2723 }
2724 // *** Light XML Library Files *** //
2725 xmlGetValues("light_xml_library_file", "helios", light_xml_library_files);
2726 possible_light_spectra.clear();
2727 for (auto &xml_library_file: light_xml_library_files) {
2728 if (xml_library_file.empty() || !std::filesystem::exists(xml_library_file)) {
2729 continue;
2730 }
2731 std::vector<std::string> current_light_file = get_xml_node_values(xml_library_file, "label", "globaldata_vec2");
2732 possible_light_spectra.insert(possible_light_spectra.end(), current_light_file.begin(), current_light_file.end());
2733 }
2734 // OBJECT BLOCK
2735 obj_names_dict.clear();
2736 obj_names_dict = getNodeLabels("label", "object", obj_names);
2737 obj_names_set = std::set<std::string>{obj_names.begin(), obj_names.end()};
2738 if (!obj_names.empty())
2739 current_obj = obj_names[0];
2740 xmlGetValues("file", "object", obj_files);
2741 xmlGetValues("position", "object", obj_positions);
2742 xmlGetValues("orientation", "object", obj_orientations);
2743 xmlGetValues("scale", "object", obj_scales);
2744 prev_obj_positions = obj_positions;
2745 prev_obj_orientations = obj_orientations;
2746 prev_obj_scales = obj_scales;
2747 obj_data_groups.clear();
2748 xmlGetValues("data_group", "object", obj_data_groups);
2749 obj_colors.clear();
2750 xmlGetValues("color", "object", obj_colors);
2751
2752 for (auto &obj: objects_dict) {
2753 deleteObject(obj.second.name);
2754 }
2755 objects_dict.clear();
2756 for (int i = 0; i < obj_files.size(); i++) {
2757 object new_object;
2758 std::vector<uint> new_UUIDs;
2759 std::string new_obj_file = obj_files[i];
2760 if (std::filesystem::path(new_obj_file).extension() == ".obj") {
2761 new_UUIDs = context->loadOBJ(new_obj_file.c_str());
2762 } else if (std::filesystem::path(new_obj_file).extension() == ".ply") {
2763 new_UUIDs = context->loadPLY(new_obj_file.c_str());
2764 } else {
2765 std::cout << "Failed to load object file " << new_obj_file << "." << std::endl;
2766 }
2767 // check for MTL file
2768 std::filesystem::path mtl_path(new_obj_file);
2769 mtl_path.replace_extension("mtl");
2770 if (std::filesystem::exists(mtl_path)) {
2771 new_object.use_texture_file = true;
2772 } else {
2773 new_object.use_texture_file = false;
2774 // Use material system for object color
2775 std::string obj_material = "projectbuilder_obj_" + std::to_string(i);
2776 if (!context->doesMaterialExist(obj_material)) {
2777 context->addMaterial(obj_material);
2778 }
2779 context->setMaterialColor(obj_material, make_RGBAcolor(obj_colors[i], 1.0f));
2780 context->assignMaterialToPrimitive(new_UUIDs, obj_material);
2781 }
2782 context->scalePrimitive(new_UUIDs, obj_scales[i]);
2783 context->rotatePrimitive(new_UUIDs, deg2rad(obj_orientations[i].x), "x");
2784 context->rotatePrimitive(new_UUIDs, deg2rad(obj_orientations[i].y), "y");
2785 context->rotatePrimitive(new_UUIDs, deg2rad(obj_orientations[i].z), "z");
2786 context->translatePrimitive(new_UUIDs, obj_positions[i]);
2787 obj_UUIDs.push_back(new_UUIDs);
2788 new_object.index = obj_idx;
2789 obj_idx++;
2790 new_object.name = obj_names[i];
2791 new_object.file = obj_files[i];
2792 new_object.data_group = obj_data_groups[i];
2793 new_object.UUIDs = new_UUIDs;
2794 new_object.position = obj_positions[i];
2795 new_object.prev_position = obj_positions[i];
2796 new_object.orientation = obj_orientations[i];
2797 new_object.prev_orientation = obj_orientations[i];
2798 new_object.scale = obj_scales[i];
2799 new_object.prev_scale = obj_scales[i];
2800 new_object.color = obj_colors[i];
2801 new_object.prev_color = obj_colors[i];
2802 new_object.is_dirty = false;
2803 objects_dict[new_object.name] = new_object;
2804 }
2805// CANOPY BLOCK
2806#ifdef ENABLE_PLANT_ARCHITECTURE
2807 canopy_labels.clear();
2808 canopy_labels_dict = getNodeLabels("label", "canopy_block", canopy_labels);
2809 for (auto canopy_label_: canopy_labels) {
2810 canopy_labels_set.insert(canopy_label_);
2811 }
2812 if (!canopy_labels.empty())
2813 current_canopy = canopy_labels[0];
2814 xmlGetValue("canopy_origin", "canopy_block", canopy_origin);
2815 xmlGetValue("plant_count", "canopy_block", plant_count);
2816 xmlGetValue("plant_spacing", "canopy_block", plant_spacing);
2817 xmlGetValue("plant_library_name", "canopy_block", plant_library_name);
2818 xmlGetValue("plant_age", "canopy_block", plant_age);
2819 xmlGetValue("ground_clipping_height", "canopy_block", ground_clipping_height);
2820 canopy_origins.clear();
2821 xmlGetValues("canopy_origin", "canopy_block", canopy_origins);
2822 plant_counts.clear();
2823 xmlGetValues("plant_count", "canopy_block", plant_counts);
2824 plant_spacings.clear();
2825 xmlGetValues("plant_spacing", "canopy_block", plant_spacings);
2826 plant_library_names.clear();
2827 xmlGetValues("plant_library_name", "canopy_block", plant_library_names);
2828 for (int i = 0; i < plant_library_names.size(); i++) {
2829 plant_library_names_verbose.push_back(plant_type_verbose_lookup[plant_library_names[i]]);
2830 }
2831 plant_ages.clear();
2832 xmlGetValues("plant_age", "canopy_block", plant_ages);
2833 ground_clipping_heights.clear();
2834 xmlGetValues("ground_clipping_height", "canopy_block", ground_clipping_heights);
2835 canopy_data_groups.clear();
2836 xmlGetValues("data_group", "canopy_block", canopy_data_groups);
2837
2838 canopy_dict.clear();
2839 for (int i = 0; i < canopy_labels.size(); i++) {
2840 canopy new_canopy;
2841 new_canopy.idx = canopy_idx;
2842 canopy_idx++;
2843 new_canopy.age = plant_ages[i];
2844 new_canopy.ground_clipping_height = ground_clipping_heights[i];
2845 new_canopy.label = canopy_labels[i];
2846 new_canopy.library_name = plant_library_names[i];
2847 new_canopy.library_name_verbose = plant_library_names_verbose[i];
2848 new_canopy.IDs = canopy_IDs[i];
2849 new_canopy.individual_plant_locations = individual_plant_locations[i];
2850 new_canopy.plant_spacing = plant_spacings[i];
2851 new_canopy.plant_count = plant_counts[i];
2852 new_canopy.origin = canopy_origins[i];
2853 new_canopy.data_group = canopy_data_groups[i];
2854 new_canopy.is_dirty = false;
2855 canopy_dict[new_canopy.label] = new_canopy;
2856 }
2857#endif
2858
2859// RIG BLOCK
2860#ifdef ENABLE_RADIATION_MODEL
2861 rig_labels.clear();
2862 rig_labels_set.clear();
2863 write_depth.clear();
2864 write_norm_depth.clear();
2865 write_segmentation_mask.clear();
2866 rig_dict = getNodeLabels("label", "rig", rig_labels);
2867 for (auto rig: rig_labels) {
2868 rig_labels_set.insert(rig);
2869 rig_position_noise.push_back(std::vector<distribution>{distribution{}, distribution{}, distribution{}});
2870 rig_lookat_noise.push_back(std::vector<distribution>{distribution{}, distribution{}, distribution{}});
2871 write_depth.push_back(false);
2872 write_norm_depth.push_back(false);
2873 write_segmentation_mask.push_back(false);
2874 }
2875 current_rig = rig_labels[0];
2876 xmlGetValues("color", "rig", rig_colors);
2877 xmlGetValue("camera_position", "rig", camera_position);
2878 xmlGetValue("camera_lookat", "rig", camera_lookat);
2879 xmlGetValue("camera_label", "rig", camera_label);
2880 camera_positions.clear();
2881 xmlGetValues("camera_position", "rig", camera_positions);
2882 camera_position_vec.clear();
2883 xmlGetValues("camera_position", "rig", camera_position_vec);
2884 camera_lookats.clear();
2885 xmlGetValues("camera_lookat", "rig", camera_lookats);
2886 camera_lookat_vec.clear();
2887 xmlGetValues("camera_lookat", "rig", camera_lookat_vec);
2888 camera_labels.clear();
2889 xmlGetValues("camera_label", "rig", camera_labels);
2890 rig_camera_labels.clear();
2891 xmlGetValues("camera_label", "rig", rig_camera_labels);
2892 keypoint_frames.clear();
2893 getKeypoints("keypoint", "camera_position", keypoint_frames);
2894 current_keypoint = std::to_string(keypoint_frames[0][0]);
2895 num_images_vec.clear();
2896 xmlGetValues("images", "rig", num_images_vec);
2897 write_depth.clear();
2898 write_norm_depth.clear();
2899 write_segmentation_mask.clear();
2900 std::vector<int> write_depth_{};
2901 std::vector<int> write_norm_depth_{};
2902 std::vector<int> write_segmentation_mask_{};
2903 xmlGetValues("depth", "rig", write_depth_);
2904 xmlGetValues("normdepth", "rig", write_norm_depth_);
2905 xmlGetValues("segmentation", "rig", write_segmentation_mask_);
2906 for (int i = 0; i < write_depth_.size(); i++) {
2907 if (write_depth_[i] == 1) {
2908 write_depth.push_back(true);
2909 } else {
2910 write_depth.push_back(false);
2911 }
2912 if (write_norm_depth_[i] == 1) {
2913 write_norm_depth.push_back(true);
2914 } else {
2915 write_norm_depth.push_back(false);
2916 }
2917 if (write_segmentation_mask_[i] == 1) {
2918 write_segmentation_mask.push_back(true);
2919 } else {
2920 write_segmentation_mask.push_back(false);
2921 }
2922 }
2923 // Ensure write vectors are properly sized even if no XML values were found
2924 while (write_depth.size() < rig_labels.size()) {
2925 write_depth.push_back(false);
2926 write_norm_depth.push_back(false);
2927 write_segmentation_mask.push_back(false);
2928 }
2929 // CAMERA BLOCK
2930 camera_names.clear();
2931 camera_names_set.clear();
2932 camera_dict = getNodeLabels("label", "camera", camera_names);
2933 current_cam = camera_names[0];
2934 xmlGetValue("camera_resolution", "camera", camera_resolution);
2935 xmlGetValue("focal_plane_distance", "camera", focal_plane_distance);
2936 xmlGetValue("lens_diameter", "camera", lens_diameter);
2937 xmlGetValue("FOV_aspect_ratio", "camera", FOV_aspect_ratio);
2938 xmlGetValue("HFOV", "camera", HFOV);
2939 camera_resolutions.clear();
2940 xmlGetValues("camera_resolution", "camera", camera_resolutions);
2941 camera_calibrations.clear();
2942 for (std::string &camera: camera_names) {
2943 camera_calibrations.push_back(std::map<std::string, std::string>{});
2944 for (std::string &band: bandlabels) {
2945 xmlGetValue("camera_calibration_" + band, "camera", camera_calibrations[camera_dict[camera]][band]);
2946 }
2947 camera_names_set.insert(camera);
2948 }
2949 focal_plane_distances.clear();
2950 xmlGetValues("focal_plane_distance", "camera", focal_plane_distances);
2951 lens_diameters.clear();
2952 xmlGetValues("lens_diameter", "camera", lens_diameters);
2953 FOV_aspect_ratios.clear();
2954 xmlGetValues("FOV_aspect_ratio", "camera", FOV_aspect_ratios);
2955 HFOVs.clear();
2956 xmlGetValues("HFOV", "camera", HFOVs);
2957 // LIGHT BLOCK
2958 light_types.clear();
2959 xmlGetValues("light_type", "light", light_types);
2960 light_direction_vec.clear();
2961 xmlGetValues("light_direction", "light", light_direction_vec);
2962 light_direction_sph_vec.clear();
2963 for (vec3 vec: light_direction_vec) {
2964 light_direction_sph_vec.push_back(cart2sphere(vec));
2965 }
2966 light_rotation_vec.clear();
2967 xmlGetValues("light_rotation", "light", light_rotation_vec);
2968 light_size_vec.clear();
2969 xmlGetValues("light_size", "light", light_size_vec);
2970 light_flux_vec.clear();
2971 xmlGetValues("light_source_flux", "light", light_flux_vec);
2972 light_radius_vec.clear();
2973 xmlGetValues("light_radius", "light", light_radius_vec);
2974 light_spectra.clear();
2975 xmlGetValues("light_spectra", "light", light_spectra);
2976 light_names.clear();
2977 light_names_set.clear();
2978 light_dict = getNodeLabels("label", "light", light_names);
2979 for (auto &light: light_names) {
2980 light_names_set.insert(light);
2981 }
2982 current_light = light_names[0];
2983 rig_light_labels.clear();
2984 xmlGetValues("light_label", "rig", rig_light_labels);
2985 // RADIATION BLOCK
2986 xmlGetValue("direct_ray_count", "radiation", direct_ray_count);
2987 xmlGetValue("diffuse_ray_count", "radiation", diffuse_ray_count);
2988 xmlGetValue("diffuse_extinction_coeff", "radiation", diffuse_extinction_coeff);
2989 xmlGetValue("scattering_depth", "radiation", scattering_depth);
2990 xmlGetValue("air_turbidity", "radiation", air_turbidity);
2991 xmlGetValues("load_xml_library_file", "radiation", xml_library_files);
2992 possible_spectra.clear();
2993 for (auto &xml_library_file: xml_library_files) {
2994 if (xml_library_file.empty() || !std::filesystem::exists(xml_library_file)) {
2995 continue;
2996 }
2997 std::vector<std::string> current_spectra_file = get_xml_node_values(xml_library_file, "label", "globaldata_vec2");
2998 for (int i = 0; i < current_spectra_file.size(); i++) {
2999 possible_spectra.insert(current_spectra_file[i]);
3000 }
3001 }
3002 xmlGetValue("solar_direct_spectrum", "radiation", solar_direct_spectrum);
3003 xmlGetValue("leaf_reflectivity_spectrum", "radiation", leaf_reflectivity_spectrum);
3004 xmlGetValue("leaf_transmissivity_spectrum", "radiation", leaf_transmissivity_spectrum);
3005 xmlGetValue("leaf_emissivity", "radiation", leaf_emissivity);
3006 xmlGetValue("ground_reflectivity_spectrum", "radiation", ground_reflectivity_spectrum);
3007 primitive_values.clear();
3008 for (std::string band: bandlabels) {
3009 primitive_values[band];
3010 for (std::string prim: primitive_names) {
3011 primitive_values[band][prim] = {ground_reflectivity, ground_transmissivity, ground_emissivity};
3012 }
3013 }
3014 primitive_spectra.clear();
3015 primitive_spectra = {{"All", {reflectivity_spectrum, transmissivity_spectrum, emissivity_spectrum}},
3016 {"ground", {ground_reflectivity_spectrum, ground_transmissivity_spectrum, ground_emissivity_spectrum}},
3017 {"leaf", {leaf_reflectivity_spectrum, leaf_transmissivity_spectrum, leaf_emissivity_spectrum}},
3018 {"petiolule", {petiolule_reflectivity_spectrum, petiolule_transmissivity_spectrum, petiolule_emissivity_spectrum}},
3019 {"petiole", {petiole_reflectivity_spectrum, petiole_transmissivity_spectrum, petiole_emissivity_spectrum}},
3020 {"internode", {internode_reflectivity_spectrum, internode_transmissivity_spectrum, internode_emissivity_spectrum}},
3021 {"peduncle", {peduncle_reflectivity_spectrum, peduncle_transmissivity_spectrum, peduncle_emissivity_spectrum}},
3022 {"petal", {petal_reflectivity_spectrum, petal_transmissivity_spectrum, petal_emissivity_spectrum}},
3023 {"pedicel", {pedicel_reflectivity_spectrum, pedicel_transmissivity_spectrum, pedicel_emissivity_spectrum}},
3024 {"fruit", {fruit_reflectivity_spectrum, fruit_transmissivity_spectrum, fruit_emissivity_spectrum}}};
3025 for (std::string prim: primitive_names) {
3026 if (prim == "All")
3027 continue;
3028 std::string default_spectrum = "";
3029 // Reflectivity
3030 xmlGetValue(prim + "_reflectivity_spectrum", "radiation", default_spectrum);
3031 if (!default_spectrum.empty()) {
3032 primitive_spectra[prim][0] = default_spectrum;
3033 primitive_continuous[prim][0] = true;
3034 } else {
3035 primitive_continuous[prim][0] = false;
3036 }
3037 // Transmissivity
3038 default_spectrum = "";
3039 xmlGetValue(prim + "_transmissivity_spectrum", "radiation", default_spectrum);
3040 if (!default_spectrum.empty()) {
3041 primitive_spectra[prim][1] = default_spectrum;
3042 primitive_continuous[prim][1] = true;
3043 } else {
3044 primitive_continuous[prim][1] = false;
3045 }
3046 for (std::string band: bandlabels) {
3047 if (band == "All")
3048 continue;
3049 xmlGetValue(prim + "_reflectivity", "radiation", primitive_values[band][prim][0]);
3050 xmlGetValue(prim + "_transmissivity", "radiation", primitive_values[band][prim][1]);
3051 xmlGetValue(prim + "_emissivity", "radiation", primitive_values[band][prim][2]);
3052 }
3053 }
3054#endif
3055}
3056
3057void ProjectBuilder::xmlGetValues(std::string xml_path) {
3058 xml_input_file = xml_path;
3059 if (!open_xml_file(xml_input_file, xmldoc, xml_error_string)) {
3060 helios_runtime_error(xml_error_string);
3061 }
3062 xmlGetValues();
3063}
3064
3065void ProjectBuilder::calculationTab() {
3066#ifdef ENABLE_HELIOS_VISUALIZER
3067 // prim
3068 for (auto &prim_name: primitive_names_set) {
3069 if (calculation_selection_primitive.find(prim_name) == calculation_selection_primitive.end()) {
3070 calculation_selection_primitive[prim_name] = false;
3071 }
3072 }
3073 std::vector<std::string> primitive_labels = context->listAllPrimitiveDataLabels();
3074 calculation_variable_choices.clear();
3075 for (auto &label: primitive_labels) {
3076 HeliosDataType dtype = context->getPrimitiveDataType(label.c_str());
3077 if (heliosNumericTypes.find(dtype) != heliosNumericTypes.end())
3078 calculation_variable_choices.insert(label);
3079 }
3080 std::vector<std::string> global_data = context->listGlobalData();
3081 for (auto &data: global_data) {
3082 HeliosDataType dtype = context->getGlobalDataType(data.c_str());
3083 if (heliosNumericTypes.find(dtype) != heliosNumericTypes.end())
3084 calculation_variable_choices.insert(data);
3085 }
3086
3087 // data group
3088 for (auto &data_group: data_groups_set) {
3089 if (calculation_selection_datagroup.find(data_group) == calculation_selection_datagroup.end()) {
3090 calculation_selection_datagroup[data_group] = false;
3091 }
3092 }
3093 // data group popup
3094 if (ImGui::BeginPopup("calculation_select_popup_datagroup")) {
3095 for (auto &calculation_pair: calculation_selection_datagroup) {
3096 ImGui::Selectable(calculation_pair.first.c_str(), &calculation_pair.second, ImGuiSelectableFlags_DontClosePopups);
3097 }
3098 ImGui::EndPopup();
3099 }
3100 if (ImGui::Button("Select Data Groups")) {
3101 ImGui::OpenPopup("calculation_select_popup_datagroup");
3102 }
3103 ImGui::SameLine();
3104 ImGui::Text("Data Groups:");
3105 int idx = 0;
3106 if (calculation_selection_datagroup["All"]) {
3107 ImGui::SameLine();
3108 ImGui::Text("All");
3109 } else {
3110 for (auto &calculation_pair: calculation_selection_datagroup) {
3111 if (calculation_pair.second) {
3112 ImGui::SameLine(), ImGui::Text("%i. %s", idx, calculation_pair.first.c_str());
3113 idx++;
3114 }
3115 }
3116 }
3117
3118 // prim popup
3119 if (ImGui::BeginPopup("calculation_select_popup_prim")) {
3120 for (auto &calculation_pair: calculation_selection_primitive) {
3121 ImGui::Selectable(calculation_pair.first.c_str(), &calculation_pair.second, ImGuiSelectableFlags_DontClosePopups);
3122 }
3123 ImGui::EndPopup();
3124 }
3125 if (ImGui::Button("Select Primitives")) {
3126 ImGui::OpenPopup("calculation_select_popup_prim");
3127 }
3128 ImGui::SameLine();
3129 ImGui::Text("Primitive Types:");
3130 idx = 0;
3131 if (calculation_selection_primitive["All"]) {
3132 ImGui::SameLine();
3133 ImGui::Text("All");
3134 } else {
3135 for (auto &calculation_pair: calculation_selection_primitive) {
3136 if (calculation_pair.second) {
3137 ImGui::SameLine(), ImGui::Text("%i. %s", idx, calculation_pair.first.c_str());
3138 idx++;
3139 }
3140 }
3141 }
3142 // Global Data Calculation
3143 ImGui::SetWindowFontScale(1.25f);
3144 ImGui::Text("Global Data:");
3145 ImGui::SetWindowFontScale(1.0f);
3146 for (int i = 0; i < calculation_variables_global.size(); i++) {
3147 if (i > 0) {
3148 ImGui::SetNextItemWidth(40);
3149 dropDown("##operator" + std::to_string(i), calculation_operators_global[i - 1], calculation_operators_choices);
3150 }
3151 ImGui::Text("Scalar:");
3152 ImGui::SameLine();
3153 ImGui::SetNextItemWidth(50);
3154 std::string scalar_label = "##Scalar" + std::to_string(i);
3155 ImGui::InputFloat(scalar_label.c_str(), &calculation_scalars_global[i]);
3156 ImGui::SameLine();
3157 ImGui::Text("Variable:");
3158 ImGui::SameLine();
3159 ImGui::SetNextItemWidth(100);
3160 dropDown("##Variable" + std::to_string(i), calculation_variables_global[i], calculation_variable_choices);
3161 ImGui::SameLine();
3162 ImGui::Text("Aggregate:");
3163 ImGui::SameLine();
3164 ImGui::SetNextItemWidth(100);
3165 dropDown("##Operation" + std::to_string(i), calculation_aggregations[i], calculation_aggregation_choices);
3166 if (i == calculation_variables_global.size() - 1) {
3167 ImGui::SameLine();
3168 if (ImGui::Button("Add Operand")) {
3169 calculation_variables_global.push_back("");
3170 calculation_scalars_global.push_back(1.0);
3171 calculation_operators_global.push_back("+");
3172 calculation_aggregations.push_back("Mean");
3173 }
3174 if (i > 0) {
3175 ImGui::SameLine();
3176 if (ImGui::Button("Remove")) {
3177 calculation_variables_global.pop_back();
3178 calculation_scalars_global.pop_back();
3179 calculation_operators_global.pop_back();
3180 calculation_aggregations.pop_back();
3181 }
3182 }
3183 }
3184 }
3185 if (ImGui::Button("Calculate Result:")) {
3186 globalCalculation();
3187 }
3188 ImGui::SameLine();
3189 ImGui::Text("%s", std::to_string(calculation_result_global).c_str());
3190 ImGui::SameLine();
3191 if (ImGui::Button("Save to Global Data")) {
3192 context->setGlobalData(calculation_name_global.c_str(), calculation_result_global);
3193 }
3194 ImGui::SameLine();
3195 ImGui::SetNextItemWidth(100);
3196 ImGui::InputText("##global_data_name", &calculation_name_global);
3197
3198 // Primitive Data Calculation
3199 ImGui::SetWindowFontScale(1.25f);
3200 ImGui::Text("Primitive Data:");
3201 ImGui::SetWindowFontScale(1.0f);
3202 for (int i = 0; i < calculation_variables_primitive.size(); i++) {
3203 if (i > 0) {
3204 ImGui::SetNextItemWidth(40);
3205 dropDown("##operator_primitive" + std::to_string(i), calculation_operators_primitive[i - 1], calculation_operators_choices);
3206 }
3207 ImGui::Text("Scalar:");
3208 ImGui::SameLine();
3209 ImGui::SetNextItemWidth(50);
3210 std::string scalar_label = "##Scalar_primitive-" + std::to_string(i);
3211 ImGui::InputFloat(scalar_label.c_str(), &calculation_scalars_primitive[i]);
3212 ImGui::SameLine();
3213 ImGui::Text("Variable:");
3214 ImGui::SameLine();
3215 ImGui::SetNextItemWidth(100);
3216 dropDown("##Variable_primitive" + std::to_string(i), calculation_variables_primitive[i], calculation_variable_choices);
3217 if (i == calculation_variables_primitive.size() - 1) {
3218 ImGui::SameLine();
3219 if (ImGui::Button("Add Operand##primitive")) {
3220 calculation_variables_primitive.push_back("");
3221 calculation_scalars_primitive.push_back(1.0);
3222 calculation_operators_primitive.push_back("+");
3223 }
3224 if (i > 0) {
3225 ImGui::SameLine();
3226 if (ImGui::Button("Remove##primitive")) {
3227 calculation_variables_primitive.pop_back();
3228 calculation_scalars_primitive.pop_back();
3229 calculation_operators_primitive.pop_back();
3230 }
3231 }
3232 }
3233 }
3234 ImGui::Text("Save Primitive Data:");
3235 ImGui::SameLine();
3236 ImGui::SetNextItemWidth(80);
3237 ImGui::InputText("##save_data_name", &calculation_name_primitive);
3238 ImGui::SameLine();
3239 if (ImGui::Button("Save to Primitive Data")) {
3240 savePrimitiveCalculation();
3241 }
3242#endif
3243}
3244
3245void ProjectBuilder::cameraTab() {
3246#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_RADIATION_MODEL)
3247 // LOAD XML LIBRARY FILE
3248 ImGui::SetNextItemWidth(60);
3249 if (ImGui::Button("Load XML Library File")) {
3250 std::string new_xml_library_file = file_dialog();
3251 if (!new_xml_library_file.empty() && std::filesystem::exists(new_xml_library_file)) {
3252 if (camera_xml_library_files.find(new_xml_library_file) == camera_xml_library_files.end()) {
3253 camera_xml_library_files.insert(new_xml_library_file);
3254 std::vector<std::string> current_camera_file = get_xml_node_values(new_xml_library_file, "label", "globaldata_vec2");
3255 possible_camera_calibrations.insert(possible_camera_calibrations.end(), current_camera_file.begin(), current_camera_file.end());
3256 }
3257 context->loadXML(new_xml_library_file.c_str());
3258 }
3259 }
3260
3261 // ####### ADD BAND GROUP ####### //
3262 ImGui::SetWindowFontScale(1.25f);
3263 ImGui::Text("Band Groups:");
3264 ImGui::SetWindowFontScale(1.0f);
3265 dropDown("##band_group_combo", current_band_group, band_group_names);
3266 ImGui::SameLine();
3267 if (ImGui::Button("Add Band Group")) {
3268 std::string default_band_group_label = "band_group";
3269 std::string new_band_group_label = "band_group_0";
3270 int count = 0;
3271 while (band_group_lookup.find(new_band_group_label) != band_group_lookup.end()) {
3272 count++;
3273 new_band_group_label = default_band_group_label + "_" + std::to_string(count);
3274 }
3275 std::vector<std::string> new_band_group_vector;
3276 new_band_group_vector.push_back("red");
3277 new_band_group_vector.push_back("green");
3278 new_band_group_vector.push_back("blue");
3279 bandGroup new_band_group{new_band_group_vector, false, false, false};
3280 band_group_lookup[new_band_group_label] = new_band_group;
3281 band_group_names.insert(new_band_group_label);
3282 current_band_group = new_band_group_label;
3283 }
3284 if (!current_band_group.empty()) {
3285 ImGui::SetNextItemWidth(100);
3286 std::string prev_group_name = current_band_group;
3287 ImGui::InputText("Group Name", &current_band_group);
3288 if (current_band_group.empty() || band_group_lookup.find(current_band_group) != band_group_lookup.end()) {
3289 current_band_group = prev_group_name;
3290 }
3291 if (current_band_group != prev_group_name) {
3292 bandGroup temp = band_group_lookup[prev_group_name];
3293 std::map<std::string, bandGroup>::iterator current_band_group_iter = band_group_lookup.find(prev_group_name);
3294 if (current_band_group_iter != band_group_lookup.end()) {
3295 band_group_lookup.erase(current_band_group_iter);
3296 }
3297 band_group_lookup[current_band_group] = temp;
3298 band_group_names.erase(prev_group_name);
3299 band_group_names.insert(current_band_group);
3300 }
3301 ImGui::SameLine();
3302 if (ImGui::Button("Delete Group")) {
3303 band_group_names.erase(current_band_group);
3304 band_group_lookup.erase(current_band_group);
3305 current_band_group = "";
3306 }
3307 ImGui::Checkbox("Grayscale", &band_group_lookup[current_band_group].grayscale);
3308 ImGui::SameLine();
3309 ImGui::Checkbox("Norm", &band_group_lookup[current_band_group].norm);
3310 if (std::find(band_group_lookup[current_band_group].bands.begin(), band_group_lookup[current_band_group].bands.end(), "red") != band_group_lookup[current_band_group].bands.end() &&
3311 std::find(band_group_lookup[current_band_group].bands.begin(), band_group_lookup[current_band_group].bands.end(), "green") != band_group_lookup[current_band_group].bands.end() &&
3312 std::find(band_group_lookup[current_band_group].bands.begin(), band_group_lookup[current_band_group].bands.end(), "blue") != band_group_lookup[current_band_group].bands.end()) {
3313 band_group_lookup[current_band_group].hdr = true;
3314 }
3315 // Band 1
3316 ImGui::SetNextItemWidth(100);
3317 dropDown("##band_1_combo", band_group_lookup[current_band_group].bands[0], bandlabels);
3318 if (!band_group_lookup[current_band_group].grayscale) {
3319 // Band 2
3320 ImGui::SameLine();
3321 ImGui::SetNextItemWidth(100);
3322 dropDown("##band_2_combo", band_group_lookup[current_band_group].bands[1], bandlabels);
3323 // Band 3
3324 ImGui::SameLine();
3325 ImGui::SetNextItemWidth(100);
3326 dropDown("##band_3_combo", band_group_lookup[current_band_group].bands[2], bandlabels);
3327 ImGui::SameLine();
3328 ImGui::Text("Select Bands");
3329 } else {
3330 ImGui::SameLine();
3331 ImGui::Text("Select Band");
3332 }
3333 }
3334 ImGui::SetWindowFontScale(1.25f);
3335 ImGui::Text("Edit Camera:");
3336 ImGui::SetWindowFontScale(1.0f);
3337 if (ImGui::BeginCombo("##camera_combo", current_cam.c_str())) {
3338 for (int n = 0; n < camera_names.size(); n++) {
3339 bool is_cam_selected = (current_cam == camera_names[n]);
3340 if (ImGui::Selectable(camera_names[n].c_str(), is_cam_selected))
3341 current_cam = camera_names[n];
3342 if (is_cam_selected)
3343 ImGui::SetItemDefaultFocus();
3344 }
3345 ImGui::EndCombo();
3346 }
3347 ImGui::SameLine();
3348 if (ImGui::Button("Add New Camera")) {
3349 std::string default_cam_name = "camera";
3350 std::string new_cam_name = "camera_0";
3351 int count = 0;
3352 while (camera_dict.find(new_cam_name) != camera_dict.end()) {
3353 count++;
3354 new_cam_name = default_cam_name + "_" + std::to_string(count);
3355 }
3356 camera_dict.insert({new_cam_name, scast<int>(camera_names.size())});
3357 camera_resolutions.push_back(camera_resolution);
3358 camera_calibrations.push_back(camera_calibrations[camera_dict[current_cam]]);
3359 focal_plane_distances.push_back(focal_plane_distance);
3360 lens_diameters.push_back(lens_diameter);
3361 FOV_aspect_ratios.push_back(FOV_aspect_ratio);
3362 HFOVs.push_back(HFOV);
3363 camera_names.push_back(new_cam_name);
3364 std::string parent = "camera";
3365 pugi::xml_node camera_block = helios.child(parent.c_str());
3366 pugi::xml_node new_cam_node = helios.append_copy(camera_block);
3367 std::string name = "label";
3368 pugi::xml_attribute node_label = new_cam_node.attribute(name.c_str());
3369 node_label.set_value(new_cam_name.c_str());
3370 current_cam = new_cam_name;
3371 }
3372 ImGui::SetNextItemWidth(100);
3373 std::string prev_cam_name = camera_names[camera_dict[current_cam]];
3374 ImGui::InputText("##cam_name", &camera_names[camera_dict[current_cam]]);
3375 if (camera_names[camera_dict[current_cam]] != prev_cam_name) {
3376 int temp = camera_dict[current_cam];
3377 current_cam = camera_names[camera_dict[current_cam]];
3378 std::map<std::string, int>::iterator current_cam_iter = camera_dict.find(prev_cam_name);
3379 if (current_cam_iter != camera_dict.end()) {
3380 camera_dict.erase(current_cam_iter);
3381 }
3382 camera_dict[current_cam] = temp;
3383 }
3384 ImGui::SameLine();
3385 ImGui::Text("Camera Label");
3386 // ####### CAMERA CALIBRATION ####### //
3387 ImGui::SetNextItemWidth(100);
3388 dropDown("##camera_calibration_band", current_calibration_band, bandlabels);
3389 ImGui::SameLine();
3390 ImGui::Text("Band");
3391 ImGui::SetNextItemWidth(250);
3392 ImGui::SameLine();
3393 dropDown("##camera_band_group_combo", camera_calibrations[camera_dict[current_cam]][current_calibration_band], possible_camera_calibrations);
3394 ImGui::SameLine();
3395 ImGui::Text("Calibration");
3396 // ####### CAMERA CALIBRATION ####### //
3397 // std::string prev_cam_calibration = camera_calibrations[camera_dict[current_cam]];
3398 // if (ImGui::BeginCombo("##camera_calibration_combo", camera_calibrations[camera_dict[current_cam]].c_str())){
3399 // for (int n = 0; n < possible_camera_calibrations.size(); n++){
3400 // bool is_cam_calibration_selected = (camera_calibrations[camera_dict[current_cam]] == possible_camera_calibrations[n]);
3401 // if (ImGui::Selectable(possible_camera_calibrations[n].c_str(), is_cam_calibration_selected))
3402 // camera_calibrations[camera_dict[current_cam]] = possible_camera_calibrations[n];
3403 // if (is_cam_calibration_selected)
3404 // ImGui::SetItemDefaultFocus();
3405 // }
3406 // ImGui::EndCombo();
3407 // }
3408 // ImGui::SameLine();
3409 // ImGui::Text("Camera Calibration");
3410 // ####### CAMERA RESOLUTION ####### //
3411 ImGui::SetNextItemWidth(90);
3412 ImGui::InputInt("##camera_resolution_x", &camera_resolutions[camera_dict[current_cam]].x);
3413 randomizePopup("camera_resolution_x_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&camera_resolutions[camera_dict[current_cam]].x));
3414 randomizerParams("camera_resolution_x_" + std::to_string(camera_dict[current_cam]));
3415 ImGui::OpenPopupOnItemClick(("randomize_camera_resolution_x_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3416 ImGui::SameLine();
3417 ImGui::SetNextItemWidth(90);
3418 ImGui::InputInt("##camera_resolution_y", &camera_resolutions[camera_dict[current_cam]].y);
3419 randomizePopup("camera_resolution_y_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&camera_resolutions[camera_dict[current_cam]].y));
3420 randomizerParams("camera_resolution_y_" + std::to_string(camera_dict[current_cam]));
3421 ImGui::OpenPopupOnItemClick(("randomize_camera_resolution_y_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3422 ImGui::SameLine();
3423 ImGui::Text("Camera Resolution");
3424 // ####### FOCAL PLANE DISTANCE ####### //
3425 ImGui::SetNextItemWidth(50);
3426 ImGui::InputFloat("Focal Plane Distance", &focal_plane_distances[camera_dict[current_cam]]);
3427 randomizePopup("focal_plane_distance_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&focal_plane_distances[camera_dict[current_cam]]));
3428 randomizerParams("focal_plane_distance_" + std::to_string(camera_dict[current_cam]));
3429 ImGui::OpenPopupOnItemClick(("randomize_focal_plane_distance_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3430 // ####### LENS DIAMETER ####### //
3431 ImGui::SetNextItemWidth(50);
3432 ImGui::InputFloat("Lens Diameter", &lens_diameters[camera_dict[current_cam]]);
3433 randomizePopup("lens_diameter_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&lens_diameters[camera_dict[current_cam]]));
3434 randomizerParams("lens_diameter_" + std::to_string(camera_dict[current_cam]));
3435 ImGui::OpenPopupOnItemClick(("randomize_lens_diameter_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3436 // ####### FOV ASPECT RATIO ####### //
3437 ImGui::SetNextItemWidth(50);
3438 ImGui::InputFloat("FOV Aspect Ratio", &FOV_aspect_ratios[camera_dict[current_cam]]);
3439 randomizePopup("FOV_aspect_ratio_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&FOV_aspect_ratios[camera_dict[current_cam]]));
3440 randomizerParams("FOV_aspect_ratio_" + std::to_string(camera_dict[current_cam]));
3441 ImGui::OpenPopupOnItemClick(("randomize_FOV_aspect_ratio_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3442 // ####### HFOV ####### //
3443 ImGui::SetNextItemWidth(50);
3444 ImGui::InputFloat("HFOV", &HFOVs[camera_dict[current_cam]]);
3445 randomizePopup("HFOV_" + std::to_string(camera_dict[current_cam]), createTaggedPtr(&HFOVs[camera_dict[current_cam]]));
3446 randomizerParams("HFOV_" + std::to_string(camera_dict[current_cam]));
3447 ImGui::OpenPopupOnItemClick(("HFOV_" + std::to_string(camera_dict[current_cam])).c_str(), ImGuiPopupFlags_MouseButtonRight);
3448 //
3449#endif
3450}
3451
3452
3453void ProjectBuilder::canopyTab() {
3454#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_PLANT_ARCHITECTURE)
3455 dropDown("##canopy_combo", current_canopy, canopy_labels_set);
3456 ImGui::SameLine();
3457 if (ImGui::Button("Add Canopy")) {
3458 addCanopy();
3459 }
3460 if (!current_canopy.empty()) {
3461 if (ImGui::Button("Update Canopy")) {
3462 updateCanopy(current_canopy);
3463 is_dirty = true;
3464 canopy_dict[current_canopy].is_dirty = false;
3465 }
3466 ImGui::SameLine();
3467 if (ImGui::Button("Delete Canopy")) {
3468 deleteCanopy(current_canopy);
3469 updatePrimitiveTypes();
3470 is_dirty = true;
3472 }
3473 if (canopy_dict[current_canopy].is_dirty) {
3474 ImGui::SameLine();
3475 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); // Red text
3476 ImGui::Text("update required");
3477 ImGui::PopStyleColor();
3478 }
3479 ImGui::SetNextItemWidth(100);
3480 std::string prev_canopy_name = canopy_dict[current_canopy].label;
3481 ImGui::InputText("##canopy_name", &canopy_dict[current_canopy].label);
3482 if (canopy_dict[current_canopy].label != prev_canopy_name && canopy_labels_set.find(canopy_dict[current_canopy].label) == canopy_labels_set.end() && !canopy_dict[current_canopy].label.empty()) {
3483 canopy temp = canopy_dict[current_canopy];
3484 current_canopy = canopy_dict[prev_canopy_name].label;
3485 std::map<std::string, canopy>::iterator current_canopy_iter = canopy_dict.find(prev_canopy_name);
3486 if (current_canopy_iter != canopy_dict.end()) {
3487 canopy_dict.erase(current_canopy_iter);
3488 }
3489 canopy_dict[current_canopy] = temp;
3490
3491 canopy_labels_set.erase(prev_canopy_name);
3492 canopy_labels_set.insert(current_canopy);
3493 } else {
3494 canopy_dict[current_canopy].label = prev_canopy_name;
3495 }
3496 ImGui::SameLine();
3497 ImGui::Text("Canopy Name");
3498 // ####### PLANT LIBRARY NAME ####### //
3499 ImGui::SetNextItemWidth(250);
3500 // ImGui::InputText("Plant Library", &plant_library_names[canopy_labels_dict[current_canopy]]);
3501 std::string prev_lib = canopy_dict[current_canopy].library_name_verbose;
3502 dropDown("Plant Library###dropdown", canopy_dict[current_canopy].library_name_verbose, plant_types_verbose);
3503 if (canopy_dict[current_canopy].library_name_verbose != prev_lib)
3504 canopy_dict[current_canopy].is_dirty = true;
3505 canopy_dict[current_canopy].library_name = plant_type_lookup[canopy_dict[current_canopy].library_name_verbose];
3506 // ######### CANOPY DATA GROUP ####### //
3507 ImGui::SetNextItemWidth(100);
3508 std::string prev_canopy_data_group = canopy_dict[current_canopy].data_group;
3509 ImGui::InputText("##canopy_data_group", &canopy_dict[current_canopy].data_group);
3510 if (canopy_dict[current_canopy].data_group == "All" || canopy_dict[current_canopy].data_group.empty()) {
3511 canopy_dict[current_canopy].data_group = prev_canopy_data_group;
3512 }
3513 if (!canopy_dict[current_canopy].data_group.empty() && prev_canopy_data_group != canopy_dict[current_canopy].data_group) {
3514 std::string new_data_group = canopy_dict[current_canopy].data_group;
3515 for (int i = 0; i < canopy_dict[current_canopy].IDs.size(); i++) {
3516 std::vector<uint> new_canopy_objIDs = plantarchitecture->getAllPlantObjectIDs(canopy_dict[current_canopy].IDs[i]);
3517 for (auto &obj: new_canopy_objIDs) {
3518 context->clearObjectData(obj, prev_canopy_data_group.c_str());
3519 context->setObjectData(obj, "data_group", new_data_group);
3520 context->setObjectData(obj, new_data_group.c_str(), 1);
3521 }
3522 // context->clearObjectData(new_canopy_objIDs, prev_canopy_data_group.c_str());
3523 // context->setObjectData(new_canopy_objIDs, "data_group", new_data_group);
3524 // context->setObjectData(new_canopy_objIDs, new_data_group.c_str(), new_canopy_objIDs);
3525 }
3526 updateDataGroups();
3527 }
3528 ImGui::SameLine();
3529 ImGui::Text("Data Group");
3530 // ####### CANOPY ORIGIN ####### //
3531 vec3 prev_canopy_origin_ = vec3(canopy_dict[current_canopy].origin);
3532 ImGui::SetNextItemWidth(60);
3533 ImGui::InputFloat("##canopy_origin_x", &canopy_dict[current_canopy].origin.x);
3534 randomizePopup("canopy_origin_x_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].origin.x));
3535 randomizerParams("canopy_origin_x_" + std::to_string(canopy_dict[current_canopy].idx));
3536 ImGui::OpenPopupOnItemClick(("randomize_canopy_origin_x_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3537 ImGui::SameLine();
3538 ImGui::SetNextItemWidth(60);
3539 ImGui::InputFloat("##canopy_origin_y", &canopy_dict[current_canopy].origin.y);
3540 randomizePopup("canopy_origin_y_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].origin.y));
3541 randomizerParams("canopy_origin_y_" + std::to_string(canopy_dict[current_canopy].idx));
3542 ImGui::OpenPopupOnItemClick(("randomize_canopy_origin_y_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3543 ImGui::SameLine();
3544 ImGui::SetNextItemWidth(60);
3545 ImGui::InputFloat("##canopy_origin_z", &canopy_dict[current_canopy].origin.z);
3546 randomizePopup("canopy_origin_z_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].origin.z));
3547 randomizerParams("canopy_origin_z_" + std::to_string(canopy_dict[current_canopy].idx));
3548 ImGui::OpenPopupOnItemClick(("randomize_canopy_origin_z_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3549 ImGui::SameLine();
3550 ImGui::Text("Canopy Origin");
3551 if (prev_canopy_origin_ != canopy_dict[current_canopy].origin) {
3552 canopy_dict[current_canopy].is_dirty = true;
3553 }
3554 // ####### PLANT COUNT ####### //
3555 int2 prev_plant_count_ = int2(canopy_dict[current_canopy].plant_count);
3556 ImGui::SetNextItemWidth(100);
3557 ImGui::InputInt("##plant_count_x", &canopy_dict[current_canopy].plant_count.x);
3558 canopy_dict[current_canopy].plant_count.x = std::max(canopy_dict[current_canopy].plant_count.x, 1);
3559 randomizePopup("plant_count_x_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].plant_count.x));
3560 randomizerParams("plant_count_x_" + std::to_string(canopy_dict[current_canopy].idx));
3561 ImGui::OpenPopupOnItemClick(("randomize_plant_count_x_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3562 ImGui::SameLine();
3563 ImGui::SetNextItemWidth(100);
3564 ImGui::InputInt("##plant_count_y", &canopy_dict[current_canopy].plant_count.y);
3565 canopy_dict[current_canopy].plant_count.y = std::max(canopy_dict[current_canopy].plant_count.y, 1);
3566 randomizePopup("plant_count_y_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].plant_count.y));
3567 randomizerParams("plant_count_y_" + std::to_string(canopy_dict[current_canopy].idx));
3568 ImGui::OpenPopupOnItemClick(("randomize_plant_count_y_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3569 ImGui::SameLine();
3570 ImGui::Text("Plant Count");
3571 if (prev_plant_count_ != canopy_dict[current_canopy].plant_count) {
3572 canopy_dict[current_canopy].is_dirty = true;
3573 }
3574 // ####### PLANT SPACING ####### //
3575 vec2 prev_plant_spacing_ = vec2(canopy_dict[current_canopy].plant_spacing);
3576 ImGui::SetNextItemWidth(50);
3577 ImGui::InputFloat("##plant_spacing_x", &canopy_dict[current_canopy].plant_spacing.x);
3578 randomizePopup("plant_spacing_x_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].plant_spacing.x));
3579 randomizerParams("plant_spacing_x_" + std::to_string(canopy_dict[current_canopy].idx));
3580 ImGui::OpenPopupOnItemClick(("randomize_plant_spacing_x_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3581 ImGui::SameLine();
3582 ImGui::SetNextItemWidth(50);
3583 ImGui::InputFloat("##plant_spacing_y", &canopy_dict[current_canopy].plant_spacing.y);
3584 randomizePopup("plant_spacing_y_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].plant_spacing.y));
3585 randomizerParams("plant_spacing_y_" + std::to_string(canopy_dict[current_canopy].idx));
3586 ImGui::OpenPopupOnItemClick(("randomize_plant_spacing_y_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3587 ImGui::SameLine();
3588 ImGui::Text("Plant Spacing");
3589 if (prev_plant_spacing_ != canopy_dict[current_canopy].plant_spacing) {
3590 canopy_dict[current_canopy].is_dirty = true;
3591 }
3592 // ####### PLANT AGE ####### //
3593 float prev_age_ = canopy_dict[current_canopy].age;
3594 ImGui::SetNextItemWidth(80);
3595 ImGui::InputFloat("Plant Age", &canopy_dict[current_canopy].age);
3596 randomizePopup("plant_age_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].age));
3597 randomizerParams("plant_age_" + std::to_string(canopy_dict[current_canopy].idx));
3598 ImGui::OpenPopupOnItemClick(("randomize_plant_age_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3599 if (prev_age_ != canopy_dict[current_canopy].age) {
3600 canopy_dict[current_canopy].is_dirty = true;
3601 }
3602 // ####### GROUND CLIPPING HEIGHT ####### //
3603 float prev_ground_clipping_height_ = canopy_dict[current_canopy].ground_clipping_height;
3604 ImGui::SetNextItemWidth(80);
3605 ImGui::InputFloat("Ground Clipping Height", &canopy_dict[current_canopy].ground_clipping_height);
3606 randomizePopup("ground_clipping_height_" + std::to_string(canopy_dict[current_canopy].idx), createTaggedPtr(&canopy_dict[current_canopy].ground_clipping_height));
3607 randomizerParams("ground_clipping_height_" + std::to_string(canopy_dict[current_canopy].idx));
3608 ImGui::OpenPopupOnItemClick(("randomize_ground_clipping_height_" + std::to_string(canopy_dict[current_canopy].idx)).c_str(), ImGuiPopupFlags_MouseButtonRight);
3609 if (prev_ground_clipping_height_ != canopy_dict[current_canopy].ground_clipping_height) {
3610 canopy_dict[current_canopy].is_dirty = true;
3611 }
3612 if (ImGui::Button("Save Canopy to OBJ/PLY File")) {
3613 std::string new_obj_file = save_as_file_dialog(std::vector<std::string>{"OBJ", "PLY"});
3614 if (!new_obj_file.empty()) {
3615 std::string file_extension = new_obj_file;
3616 size_t last_obj_file = file_extension.rfind('.');
3617 if (last_obj_file != std::string::npos) {
3618 file_extension = file_extension.substr(last_obj_file + 1);
3619 }
3620 if (file_extension == "obj" || file_extension == "ply") {
3621 if (!std::filesystem::exists(new_obj_file)) {
3622 // Create file
3623 std::ofstream outFile(new_obj_file);
3624 }
3625 if (!save_plants_individually) {
3626 saveCanopy(new_obj_file, canopy_dict[current_canopy].IDs, canopy_dict[current_canopy].origin, file_extension);
3627 } else {
3628 saveCanopy(new_obj_file, canopy_dict[current_canopy].IDs, canopy_dict[current_canopy].individual_plant_locations, file_extension);
3629 }
3630 } else {
3631 // Needs to be a obj or ply file
3632 std::cout << "Not a valid file type. Object must be saved to .obj or .ply file." << std::endl;
3633 }
3634 } else {
3635 // Not a valid file
3636 std::cout << "Not a valid file." << std::endl;
3637 }
3638 }
3639 ImGui::SameLine();
3640 ImGui::Checkbox("Save plants individually", &save_plants_individually);
3641 }
3642#endif
3643}
3644
3645
3646void ProjectBuilder::generalTab() {
3647#ifdef ENABLE_HELIOS_VISUALIZER
3648 // ####### LOCATION ####### //
3649 ImGui::SetWindowFontScale(1.25f);
3650 ImGui::Text("Visualization:");
3651 ImGui::SetWindowFontScale(1.0f);
3652 // ####### COORDINATE AXES ####### //
3653 bool enable_coords_ = enable_coordinate_axes;
3654 toggle_button("##coordinate_axes", &enable_coordinate_axes);
3655 if (enable_coords_ != enable_coordinate_axes) {
3656 if (enable_coordinate_axes) {
3657 visualizer->addCoordinateAxes(helios::make_vec3(0, 0, 0.05), helios::make_vec3(1, 1, 1), "positive");
3658 is_dirty = true;
3659 } else {
3661 is_dirty = true;
3662 }
3663 }
3664 ImGui::SameLine();
3665 if (enable_coordinate_axes) {
3666 ImGui::Text("Coordinate Axes Enabled");
3667 } else {
3668 ImGui::Text("Coordinate Axes Disabled");
3669 }
3670 // ####### COLORBAR ####### //
3671 bool enable_colorbar_ = enable_colorbar;
3672 toggle_button("##colorbar", &enable_colorbar);
3673 if (enable_colorbar_ != enable_colorbar) {
3674 if (enable_colorbar) {
3676 is_dirty = true;
3677 } else {
3679 is_dirty = true;
3680 }
3681 }
3682 ImGui::SameLine();
3683 if (enable_colorbar) {
3684 ImGui::Text("Colorbar Enabled");
3685 } else {
3686 ImGui::Text("Colorbar Disabled");
3687 }
3688 // ####### LIGHTING MODEL ####### //
3689 std::string prev_lighting_model = lighting_model;
3690 ImGui::SetNextItemWidth(120);
3691 dropDown("Lighting Model", lighting_model, lighting_models);
3692 if (prev_lighting_model != lighting_model) {
3693 if (lighting_model == "None")
3695 if (lighting_model == "Phong")
3697 if (lighting_model == "Phong Shadowed")
3699 }
3700 ImGui::SetNextItemWidth(120);
3701 // ####### LIGHTING INTENSITY ####### //
3702 ImGui::InputFloat("Light Intensity Factor", &light_intensity);
3703 visualizer->setLightIntensityFactor(light_intensity);
3704 // ####### LIGHTING DIRECTION ####### //
3705 toggle_button("##light_coord_type", &light_coord_type);
3706 ImGui::SameLine();
3707 if (light_coord_type) {
3708 SphericalCoord light_dir_sphere_ = cart2sphere(light_direction);
3709 vec2 light_dir_sphere;
3710 light_dir_sphere.x = rad2deg(light_dir_sphere_.elevation);
3711 light_dir_sphere.y = rad2deg(light_dir_sphere_.azimuth);
3712 ImGui::Text("Elevation:");
3713 ImGui::SameLine();
3714 ImGui::SetNextItemWidth(80);
3715 ImGui::InputFloat("##light_elevation", &light_dir_sphere.x);
3716 ImGui::SameLine();
3717 ImGui::Text("Azimuth:");
3718 ImGui::SameLine();
3719 ImGui::SetNextItemWidth(80);
3720 ImGui::InputFloat("##light_azimuth", &light_dir_sphere.y);
3721 ImGui::SameLine();
3722 ImGui::Text("Light Direction (Spherical)");
3723 if (light_dir_sphere.x != light_dir_sphere_.elevation || light_dir_sphere.y != light_dir_sphere_.azimuth) {
3724 SphericalCoord light_dir = make_SphericalCoord(deg2rad(light_dir_sphere.x), deg2rad(light_dir_sphere.y));
3725 light_direction = sphere2cart(light_dir);
3726 }
3727 } else {
3728 float light_dir[3];
3729 light_dir[0] = light_direction.x;
3730 light_dir[1] = light_direction.y;
3731 light_dir[2] = light_direction.z;
3732 ImGui::InputFloat3("Light Direction (Cartesian)", light_dir);
3733 light_direction.x = light_dir[0];
3734 light_direction.y = light_dir[1];
3735 light_direction.z = light_dir[2];
3736 }
3737 visualizer->setLightDirection(light_direction);
3738 // ####### LOCATION ####### //
3739 ImGui::SetWindowFontScale(1.25f);
3740 ImGui::Text("Location:");
3741 ImGui::SetWindowFontScale(1.0f);
3742 if (ImGui::Button("Update Location")) {
3744 }
3745 // ####### LATITUDE ####### //
3746 ImGui::SetNextItemWidth(100);
3747 ImGui::InputFloat("Latitude", &latitude);
3748 randomizePopup("latitude", createTaggedPtr(&latitude));
3749 randomizerParams("latitude");
3750 ImGui::OpenPopupOnItemClick("randomize_latitude", ImGuiPopupFlags_MouseButtonRight);
3751 ImGui::SameLine();
3752 // ####### LONGITUDE ####### //
3753 ImGui::SetNextItemWidth(100);
3754 ImGui::InputFloat("Longitude", &longitude);
3755 randomizePopup("longitude", createTaggedPtr(&longitude));
3756 randomizerParams("longitude");
3757 ImGui::OpenPopupOnItemClick("randomize_longitude", ImGuiPopupFlags_MouseButtonRight);
3758 // ####### UTC OFFSET ####### //
3759 ImGui::SetNextItemWidth(100);
3760 ImGui::InputInt("UTC Offset", &UTC_offset);
3761 randomizePopup("UTC_offset", createTaggedPtr(&UTC_offset));
3762 randomizerParams("UTC_offset");
3763 ImGui::OpenPopupOnItemClick("randomize_UTC_offset", ImGuiPopupFlags_MouseButtonRight);
3764 // ####### Weather File ####### //
3765 ImGui::SetNextItemWidth(60);
3766 ImGui::RadioButton("CSV", is_weather_file_csv);
3767 if (ImGui::IsItemClicked())
3768 is_weather_file_csv = true;
3769 ImGui::SameLine();
3770 ImGui::RadioButton("CIMIS", !is_weather_file_csv);
3771 if (ImGui::IsItemClicked())
3772 is_weather_file_csv = false;
3773 std::string prev_weather_file;
3774 std::string *weather_file;
3775 if (is_weather_file_csv) {
3776 ImGui::Text("CSV");
3777 weather_file = &csv_weather_file;
3778 prev_weather_file = csv_weather_file;
3779 } else {
3780 ImGui::Text("CIMIS");
3781 weather_file = &cimis_weather_file;
3782 prev_weather_file = cimis_weather_file;
3783 }
3784 ImGui::SameLine();
3785 if (ImGui::Button("Weather File")) {
3786 std::string weather_file_ = file_dialog();
3787 if (!weather_file_.empty()) {
3788 *weather_file = weather_file_;
3789 try {
3790 if (is_weather_file_csv) {
3791 context->loadTabularTimeseriesData(*weather_file, {}, ",", "YYYYMMDD", 1);
3792 } else {
3793 context->loadTabularTimeseriesData(*weather_file, {"CIMIS"}, ",");
3794 }
3795 } catch (...) {
3796 std::cout << "Failed to load weather file: " << *weather_file << std::endl;
3797 *weather_file = prev_weather_file;
3798 }
3799 } else {
3800 *weather_file = prev_weather_file;
3801 }
3802 }
3803 ImGui::SameLine();
3804 std::string shorten_weather_file = *weather_file;
3805 for (char &c: shorten_weather_file) {
3806 if (c == '\\') {
3807 c = '/';
3808 }
3809 }
3810 size_t last_weather_file = shorten_weather_file.rfind('/');
3811 if (last_weather_file != std::string::npos) {
3812 shorten_weather_file = shorten_weather_file.substr(last_weather_file + 1);
3813 }
3814 ImGui::Text("%s", shorten_weather_file.c_str());
3815 // ####### GROUND ####### //
3816 ImGui::SetWindowFontScale(1.25f);
3817 ImGui::Text("Ground:");
3818 ImGui::SetWindowFontScale(1.0f);
3819 if (ImGui::Button("Update Ground")) {
3820 updateGround();
3821 updatePrimitiveTypes();
3822 updateSpectra();
3823 is_dirty = true;
3824 }
3825 ImGui::SameLine();
3826 if (ImGui::Button("Delete Ground")) {
3827 deleteGround();
3828 updatePrimitiveTypes();
3829 updateSpectra();
3830 is_dirty = true;
3831 }
3832 // ImGui::RadioButton("Manually Set Color", ground_flag == 0); if (ImGui::IsItemClicked()) ground_flag = 0;
3833 // ImGui::SameLine();
3834 ImGui::RadioButton("Use Texture File", ground_flag == 1);
3835 if (ImGui::IsItemClicked())
3836 ground_flag = 1;
3837 ImGui::SameLine();
3838 ImGui::RadioButton("Use Model File", ground_flag == 2);
3839 if (ImGui::IsItemClicked())
3840 ground_flag = 2;
3841 if (ground_flag == 0) {
3842 // ####### GROUND COLOR ####### //
3843 ImGui::ColorEdit3("##ground_color_edit", ground_color);
3844 } else if (ground_flag == 1) {
3845 // ####### GROUND TEXTURE File ####### //
3846 ImGui::SetNextItemWidth(60);
3847 if (ImGui::Button("Ground Texture File")) {
3848 std::string ground_texture_file_ = file_dialog();
3849 if (!ground_texture_file_.empty()) {
3850 ground_texture_file = ground_texture_file_;
3851 }
3852 }
3853 ImGui::SameLine();
3854 std::string shorten = ground_texture_file;
3855 for (char &c: shorten) {
3856 if (c == '\\') {
3857 c = '/';
3858 }
3859 }
3860 size_t last = shorten.rfind('/');
3861 if (last != std::string::npos) {
3862 shorten = shorten.substr(last + 1);
3863 }
3864 ImGui::Text("%s", shorten.c_str());
3865 } else if (ground_flag == 2) {
3866 // ####### GROUND Model File ####### //
3867 ImGui::SetNextItemWidth(60);
3868 if (ImGui::Button("Ground Model File")) {
3869 std::string ground_model_file_ = file_dialog();
3870 if (!ground_model_file_.empty()) {
3871 ground_model_file = ground_model_file_;
3872 }
3873 }
3874 ImGui::SameLine();
3875 ImGui::Text("%s", shortenPath(ground_model_file).c_str());
3876 }
3877 toggle_button("##use_ground_texture_color", &use_ground_texture);
3878 // ####### GROUND COLOR ####### //
3879 if (use_ground_texture) {
3880 ImGui::SameLine();
3881 ImGui::Text("Use Ground Texture Color");
3882 } else {
3883 ImGui::SameLine();
3884 ImGui::ColorEdit3("##ground_color_edit", ground_color);
3885 ImGui::SameLine();
3886 ImGui::Text("Manually Set Ground Color");
3887 }
3888 // ####### DOMAIN ORIGIN ####### //
3889 ImGui::SetNextItemWidth(60);
3890 ImGui::InputFloat("##domain_origin_x", &domain_origin.x);
3891 randomizePopup("domain_origin_x", createTaggedPtr(&domain_origin.x));
3892 randomizerParams("domain_origin_x");
3893 ImGui::OpenPopupOnItemClick("randomize_domain_origin_x", ImGuiPopupFlags_MouseButtonRight);
3894 ImGui::SameLine();
3895 ImGui::SetNextItemWidth(60);
3896 ImGui::InputFloat("##domain_origin_y", &domain_origin.y);
3897 randomizePopup("domain_origin_y", createTaggedPtr(&domain_origin.y));
3898 randomizerParams("domain_origin_y");
3899 ImGui::OpenPopupOnItemClick("randomize_domain_origin_y", ImGuiPopupFlags_MouseButtonRight);
3900 ImGui::SameLine();
3901 ImGui::SetNextItemWidth(60);
3902 ImGui::InputFloat("##domain_origin_z", &domain_origin.z);
3903 randomizePopup("domain_origin_z", createTaggedPtr(&domain_origin.z));
3904 randomizerParams("domain_origin_z");
3905 ImGui::OpenPopupOnItemClick("randomize_domain_origin_z", ImGuiPopupFlags_MouseButtonRight);
3906 ImGui::SameLine();
3907 ImGui::Text("Domain Origin");
3908 if (ground_flag == 1) {
3909 // ####### GROUND RESOLUTION ####### //
3910 ImGui::SetNextItemWidth(100);
3911 ImGui::InputInt("##ground_resolution_x", &ground_resolution.x);
3912 randomizePopup("ground_resolution_x", createTaggedPtr(&ground_resolution.x));
3913 randomizerParams("ground_resolution_x");
3914 ImGui::OpenPopupOnItemClick("randomize_ground_resolution_x", ImGuiPopupFlags_MouseButtonRight);
3915 ImGui::SameLine();
3916 ImGui::SetNextItemWidth(100);
3917 ImGui::InputInt("##ground_resolution_y", &ground_resolution.y);
3918 randomizePopup("ground_resolution_y", createTaggedPtr(&ground_resolution.y));
3919 randomizerParams("ground_resolution_y");
3920 ImGui::OpenPopupOnItemClick("randomize_ground_resolution_y", ImGuiPopupFlags_MouseButtonRight);
3921 ImGui::SameLine();
3922 ImGui::Text("Ground Resolution");
3923 // ####### DOMAIN EXTENT ####### //
3924 ImGui::SetNextItemWidth(50);
3925 ImGui::InputFloat("##domain_extent_x", &domain_extent.x);
3926 randomizePopup("domain_extent_x", createTaggedPtr(&domain_extent.x));
3927 randomizerParams("domain_extent_x");
3928 ImGui::OpenPopupOnItemClick("randomize_domain_extent_x", ImGuiPopupFlags_MouseButtonRight);
3929 ImGui::SameLine();
3930 ImGui::SetNextItemWidth(50);
3931 ImGui::InputFloat("##domain_extent_y", &domain_extent.y);
3932 randomizePopup("domain_extent_y", createTaggedPtr(&domain_extent.y));
3933 randomizerParams("domain_extent_y");
3934 ImGui::OpenPopupOnItemClick("randomize_domain_extent_y", ImGuiPopupFlags_MouseButtonRight);
3935 ImGui::SameLine();
3936 ImGui::Text("Domain Extent");
3937 // ####### NUMBER OF TILES ####### //
3938 ImGui::SetNextItemWidth(60);
3939 int temp[2];
3940 temp[0] = num_tiles.x;
3941 temp[1] = num_tiles.y;
3942 ImGui::InputInt2("Number of Tiles", temp);
3943 num_tiles.x = temp[0];
3944 num_tiles.y = temp[1];
3945 }
3946#endif
3947}
3948
3949
3950void ProjectBuilder::objectTab() {
3951#ifdef ENABLE_HELIOS_VISUALIZER
3952 if (ImGui::Button("Load Object File")) {
3953 std::string new_obj_file = file_dialog();
3954 if (!new_obj_file.empty() && std::filesystem::exists(new_obj_file)) {
3955 if (std::filesystem::path(new_obj_file).extension() != ".obj" && std::filesystem::path(new_obj_file).extension() != ".ply") {
3956 std::cout << "Object file must have .obj or .ply extension." << std::endl;
3957 } else {
3958 object new_obj;
3959 std::vector<uint> new_UUIDs;
3960 if (std::filesystem::path(new_obj_file).extension() == ".obj") {
3961 new_UUIDs = context->loadOBJ(new_obj_file.c_str());
3962 } else if (std::filesystem::path(new_obj_file).extension() == ".ply") {
3963 new_UUIDs = context->loadPLY(new_obj_file.c_str());
3964 }
3965 // check for MTL file
3966 std::filesystem::path mtl_path(new_obj_file);
3967 mtl_path.replace_extension("mtl");
3968 if (std::filesystem::exists(mtl_path)) {
3969 new_obj.use_texture_file = true;
3970 } else {
3971 new_obj.use_texture_file = false;
3972 }
3973 // visualizer->buildContextGeometry(context);
3974 // visualizer->plotUpdate();
3975 std::string default_object_label = "object";
3976 std::string new_obj_label = "object_0";
3977 int count = 0;
3978 while (objects_dict.find(new_obj_label) != objects_dict.end()) {
3979 count++;
3980 new_obj_label = default_object_label + "_" + std::to_string(count);
3981 }
3982 obj_names_set.insert(new_obj_label);
3983 new_obj.index = obj_idx;
3984 obj_idx++;
3985 new_obj.name = new_obj_label;
3986 new_obj.file = new_obj_file;
3987 new_obj.UUIDs = new_UUIDs;
3988 new_obj.objID = context->addPolymeshObject(new_UUIDs); // TODO: change transformations to object level
3989 new_obj.position = vec3(0, 0, 0);
3990 new_obj.prev_position = vec3(0, 0, 0);
3991 new_obj.orientation = vec3(0, 0, 0);
3992 new_obj.prev_orientation = vec3(0, 0, 0);
3993 new_obj.scale = vec3(1, 1, 1);
3994 new_obj.prev_scale = vec3(1, 1, 1);
3995 new_obj.color = RGBcolor(0, 0, 1);
3996 new_obj.prev_color = RGBcolor(0, 0, 1);
3997 new_obj.data_group = "";
3998 new_obj.is_dirty = false;
3999 current_obj = new_obj_label;
4000 objects_dict[new_obj_label] = new_obj;
4001
4002 is_dirty = true;
4003 }
4004 }
4005 }
4006 if (ImGui::BeginCombo("##obj_combo", current_obj.c_str())) {
4007 for (std::string obj_name: obj_names_set) {
4008 bool is_obj_selected = (current_obj == obj_name);
4009 if (ImGui::Selectable(obj_name.c_str(), is_obj_selected))
4010 current_obj = obj_name;
4011 if (is_obj_selected)
4012 ImGui::SetItemDefaultFocus();
4013 }
4014 ImGui::EndCombo();
4015 }
4016 ImGui::SameLine();
4017 ImGui::Text("Select Object");
4018 if (!current_obj.empty()) {
4019 if (ImGui::Button("Delete Object")) {
4020 deleteObject(current_obj);
4021 }
4022 if (objects_dict[current_obj].is_dirty) {
4023 ImGui::SameLine();
4024 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); // Red text
4025 ImGui::Text("update required");
4026 ImGui::PopStyleColor();
4027 }
4028 ImGui::SetNextItemWidth(100);
4029 std::string prev_obj_name = objects_dict[current_obj].name;
4030 ImGui::InputText("##obj_name", &objects_dict[current_obj].name);
4031 if (objects_dict[current_obj].name != prev_obj_name && !objects_dict[current_obj].name.empty() && obj_names_set.find(objects_dict[current_obj].name) == obj_names_set.end()) {
4032 object temp_obj = objects_dict[prev_obj_name];
4033 current_obj = objects_dict[current_obj].name;
4034 std::map<std::string, object>::iterator delete_obj_iter = objects_dict.find(prev_obj_name);
4035 if (delete_obj_iter != objects_dict.end()) {
4036 objects_dict.erase(delete_obj_iter);
4037 }
4038 objects_dict[current_obj] = temp_obj;
4039 obj_names_set.erase(prev_obj_name);
4040 obj_names_set.insert(current_obj);
4041 } else {
4042 objects_dict[current_obj].name = prev_obj_name;
4043 }
4044 ImGui::SameLine();
4045 ImGui::Text("Object Name");
4046 if (!current_obj.empty()) {
4047 // ####### OBJECT DATA GROUP ####### //
4048 ImGui::SetNextItemWidth(100);
4049 std::string prev_obj_data_group = objects_dict[current_obj].data_group;
4050 ImGui::InputText("##obj_data_group", &objects_dict[current_obj].data_group);
4051 if (objects_dict[current_obj].data_group == "All" || objects_dict[current_obj].data_group.empty()) {
4052 objects_dict[current_obj].data_group = prev_obj_data_group;
4053 }
4054 if (!objects_dict[current_obj].data_group.empty() && prev_obj_data_group != objects_dict[current_obj].data_group) {
4055 if (context->doesObjectDataExist(objects_dict[current_obj].objID, prev_obj_data_group.c_str())) {
4056 context->clearObjectData(objects_dict[current_obj].objID, prev_obj_data_group.c_str());
4057 }
4058 std::string new_data_group = objects_dict[current_obj].data_group;
4059 context->setObjectData(objects_dict[current_obj].objID, "data_group", new_data_group);
4060 int index = objects_dict[current_obj].index;
4061 context->setObjectData(objects_dict[current_obj].objID, new_data_group.c_str(), index);
4062 updateDataGroups();
4063 }
4064 ImGui::SameLine();
4065 ImGui::Text("Data Group");
4066 bool use_obj_texture = objects_dict[current_obj].use_texture_file;
4067 toggle_button("##use_texture_file", &use_obj_texture);
4068 if (use_obj_texture != objects_dict[current_obj].use_texture_file) {
4069 objects_dict[current_obj].use_texture_file = use_obj_texture;
4070 objects_dict[current_obj].is_dirty = true;
4071 updateObject(current_obj);
4072 is_dirty = true;
4073 }
4074 ImGui::SameLine();
4075 if (!use_obj_texture) {
4076 // ####### OBJECT COLOR ####### //
4077 float col[3];
4078 col[0] = objects_dict[current_obj].color.r;
4079 col[1] = objects_dict[current_obj].color.g;
4080 col[2] = objects_dict[current_obj].color.b;
4081 ImGui::ColorEdit3("##obj_color_edit", col);
4082 if (objects_dict[current_obj].color.r != col[0] || objects_dict[current_obj].color.g != col[1] || objects_dict[current_obj].color.b != col[2]) {
4083 updateColor(current_obj, "obj", col);
4084 }
4085 ImGui::SameLine();
4086 ImGui::Text("Object Color");
4087 } else {
4088 // ####### OBJECT TEXTURE FILE ####### //
4089 ImGui::Text("Use Color from Texture File");
4090 }
4091 // ####### OBJECT SCALE ####### //
4092 ImGui::SetNextItemWidth(60);
4093 ImGui::InputFloat("##obj_scale_x", &objects_dict[current_obj].scale.x);
4094 randomizePopup("obj_scale_x_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].scale.x, &objects_dict[current_obj].is_dirty));
4095 randomizerParams("obj_scale_x_" + std::to_string(objects_dict[current_obj].index));
4096 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_x_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4097 ImGui::SameLine();
4098 ImGui::SetNextItemWidth(60);
4099 ImGui::InputFloat("##obj_scale_y", &objects_dict[current_obj].scale.y);
4100 randomizePopup("obj_scale_y_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].scale.y, &objects_dict[current_obj].is_dirty));
4101 randomizerParams("obj_scale_y_" + std::to_string(objects_dict[current_obj].index));
4102 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_y_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4103 ImGui::SameLine();
4104 ImGui::SetNextItemWidth(60);
4105 ImGui::InputFloat("##obj_scale_z", &objects_dict[current_obj].scale.z);
4106 randomizePopup("obj_scale_z_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].scale.z, &objects_dict[current_obj].is_dirty));
4107 randomizerParams("obj_scale_z_" + std::to_string(objects_dict[current_obj].index));
4108 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_z_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4109 ImGui::SameLine();
4110 ImGui::Text("Object Scale");
4111 // ####### OBJECT POSITION ####### //
4112 ImGui::SetNextItemWidth(60);
4113 ImGui::InputFloat("##obj_position_x", &objects_dict[current_obj].position.x);
4114 randomizePopup("obj_position_x_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].position.x, &objects_dict[current_obj].is_dirty));
4115 randomizerParams("obj_position_x_" + std::to_string(objects_dict[current_obj].index));
4116 ImGui::OpenPopupOnItemClick(("randomize_obj_position_x_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4117 ImGui::SameLine();
4118 ImGui::SetNextItemWidth(60);
4119 ImGui::InputFloat("##obj_position_y", &objects_dict[current_obj].position.y);
4120 randomizePopup("obj_position_y_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].position.y, &objects_dict[current_obj].is_dirty));
4121 randomizerParams("obj_position_y_" + std::to_string(objects_dict[current_obj].index));
4122 ImGui::OpenPopupOnItemClick(("randomize_obj_position_y_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4123 ImGui::SameLine();
4124 ImGui::SetNextItemWidth(60);
4125 ImGui::InputFloat("##obj_position_z", &objects_dict[current_obj].position.z);
4126 randomizePopup("obj_position_z_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].position.z, &objects_dict[current_obj].is_dirty));
4127 randomizerParams("obj_position_z_" + std::to_string(objects_dict[current_obj].index));
4128 ImGui::OpenPopupOnItemClick(("randomize_obj_position_z_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4129 ImGui::SameLine();
4130 ImGui::Text("Object Position");
4131 // ####### OBJECT ORIENTATION ####### //
4132 ImGui::SetNextItemWidth(60);
4133 ImGui::InputFloat("##obj_orientation_x", &objects_dict[current_obj].orientation.x);
4134 randomizePopup("obj_orientation_x_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].orientation.x, &objects_dict[current_obj].is_dirty));
4135 randomizerParams("obj_orientation_x_" + std::to_string(objects_dict[current_obj].index));
4136 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_x_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4137 ImGui::SameLine();
4138 ImGui::SetNextItemWidth(60);
4139 ImGui::InputFloat("##obj_orientation_y", &objects_dict[current_obj].orientation.y);
4140 randomizePopup("obj_orientation_y_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].orientation.y, &objects_dict[current_obj].is_dirty));
4141 randomizerParams("obj_orientation_y_" + std::to_string(objects_dict[current_obj].index));
4142 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_y_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4143 ImGui::SameLine();
4144 ImGui::SetNextItemWidth(60);
4145 ImGui::InputFloat("##obj_orientation_z", &objects_dict[current_obj].orientation.z);
4146 randomizePopup("obj_orientation_z_" + std::to_string(objects_dict[current_obj].index), createTaggedPtr(&objects_dict[current_obj].orientation.z, &objects_dict[current_obj].is_dirty));
4147 randomizerParams("obj_orientation_z_" + std::to_string(objects_dict[current_obj].index));
4148 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_z_" + std::to_string(objects_dict[current_obj].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4149 ImGui::SameLine();
4150 ImGui::Text("Object Orientation");
4151 if (objects_dict[current_obj].position != objects_dict[current_obj].prev_position || objects_dict[current_obj].orientation != objects_dict[current_obj].prev_orientation ||
4152 objects_dict[current_obj].scale != objects_dict[current_obj].prev_scale || objects_dict[current_obj].color != objects_dict[current_obj].prev_color) {
4153 objects_dict[current_obj].is_dirty = true;
4154 }
4155 if (objects_dict[current_obj].is_dirty && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemFocused()) {
4156 updateObject(current_obj);
4157 }
4158 }
4159 }
4160#endif
4161}
4162
4163
4164void ProjectBuilder::objectTab(std::string curr_obj_name, int id) {
4165#ifdef ENABLE_HELIOS_VISUALIZER
4166 if (ImGui::Button("Delete Object")) {
4167 deleteObject(curr_obj_name);
4168 is_dirty = true;
4169 }
4170 ImGui::SetNextItemWidth(100);
4171 std::string prev_obj_name = objects_dict[curr_obj_name].name;
4172 ImGui::InputText(("##obj_name_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].name);
4173 if (objects_dict[curr_obj_name].name != prev_obj_name && objects_dict.find(curr_obj_name) == objects_dict.end() && !objects_dict[curr_obj_name].name.empty()) {
4174 object temp_obj = objects_dict[curr_obj_name];
4175 curr_obj_name = objects_dict[curr_obj_name].name;
4176 std::map<std::string, object>::iterator delete_obj_iter = objects_dict.find(prev_obj_name);
4177 if (delete_obj_iter != objects_dict.end()) {
4178 objects_dict.erase(delete_obj_iter);
4179 }
4180
4181 objects_dict[objects_dict[curr_obj_name].name] = temp_obj;
4182
4183 obj_names_set.erase(prev_obj_name);
4184 obj_names_set.insert(objects_dict[curr_obj_name].name);
4185 } else {
4186 objects_dict[curr_obj_name].name = prev_obj_name;
4187 }
4188 ImGui::SameLine();
4189 ImGui::Text("Object Name");
4190 // ####### OBJECT SCALE ####### //
4191 vec3 prev_obj_scale = vec3(objects_dict[curr_obj_name].scale);
4192 ImGui::SetNextItemWidth(60);
4193 ImGui::InputFloat(("##obj_scale_x_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].scale.x);
4194 randomizePopup("obj_scale_x_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].scale.x, &objects_dict[curr_obj_name].is_dirty));
4195 randomizerParams("obj_scale_x_" + std::to_string(objects_dict[curr_obj_name].index));
4196 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_x_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4197 ImGui::SameLine();
4198 ImGui::SetNextItemWidth(60);
4199 ImGui::InputFloat(("##obj_scale_y_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].scale.y);
4200 randomizePopup("obj_scale_y_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].scale.y, &objects_dict[curr_obj_name].is_dirty));
4201 randomizerParams("obj_scale_y_" + std::to_string(objects_dict[curr_obj_name].index));
4202 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_y_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4203 ImGui::SameLine();
4204 ImGui::SetNextItemWidth(60);
4205 ImGui::InputFloat(("##obj_scale_z_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].scale.z);
4206 randomizePopup("obj_scale_z_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].scale.z, &objects_dict[curr_obj_name].is_dirty));
4207 randomizerParams("obj_scale_z_" + std::to_string(objects_dict[curr_obj_name].index));
4208 ImGui::OpenPopupOnItemClick(("randomize_obj_scale_z_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4209 ImGui::SameLine();
4210 ImGui::Text("Object Scale");
4211 if (prev_obj_scale != objects_dict[curr_obj_name].scale) {
4212 objects_dict[curr_obj_name].is_dirty = true;
4213 }
4214 // ####### OBJECT POSITION ####### //
4215 ImGui::SetNextItemWidth(60);
4216 vec3 prev_obj_pos = vec3(objects_dict[curr_obj_name].scale);
4217 ImGui::InputFloat(("##obj_position_x_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].position.x);
4218 randomizePopup("obj_position_x_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].position.x, &objects_dict[curr_obj_name].is_dirty));
4219 randomizerParams("obj_position_x_" + std::to_string(objects_dict[curr_obj_name].index));
4220 ImGui::OpenPopupOnItemClick(("randomize_obj_position_x_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4221 ImGui::SameLine();
4222 ImGui::SetNextItemWidth(60);
4223 ImGui::InputFloat(("##obj_position_y_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].position.y);
4224 randomizePopup("obj_position_y_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].position.y, &objects_dict[curr_obj_name].is_dirty));
4225 randomizerParams("obj_position_y_" + std::to_string(objects_dict[curr_obj_name].index));
4226 ImGui::OpenPopupOnItemClick(("randomize_obj_position_y_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4227 ImGui::SameLine();
4228 ImGui::SetNextItemWidth(60);
4229 ImGui::InputFloat(("##obj_position_z_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].position.z);
4230 randomizePopup("obj_position_z_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].position.z, &objects_dict[curr_obj_name].is_dirty));
4231 randomizerParams("obj_position_z_" + std::to_string(objects_dict[curr_obj_name].index));
4232 ImGui::OpenPopupOnItemClick(("randomize_obj_position_z_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4233 ImGui::SameLine();
4234 ImGui::Text("Object Position");
4235 if (prev_obj_pos != objects_dict[curr_obj_name].position) {
4236 objects_dict[curr_obj_name].is_dirty = true;
4237 }
4238 // ####### OBJECT ORIENTATION ####### //
4239 ImGui::SetNextItemWidth(60);
4240 vec3 prev_obj_orientation = vec3(objects_dict[curr_obj_name].orientation);
4241 ImGui::InputFloat(("##obj_orientation_x_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].orientation.x);
4242 randomizePopup("obj_orientation_x_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].orientation.x, &objects_dict[curr_obj_name].is_dirty));
4243 randomizerParams("obj_orientation_x_" + std::to_string(objects_dict[curr_obj_name].index));
4244 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_x_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4245 ImGui::SameLine();
4246 ImGui::SetNextItemWidth(60);
4247 ImGui::InputFloat(("##obj_orientation_y_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].orientation.y);
4248 randomizePopup("obj_orientation_y_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].orientation.y, &objects_dict[curr_obj_name].is_dirty));
4249 randomizerParams("obj_orientation_y_" + std::to_string(objects_dict[curr_obj_name].index));
4250 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_y_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4251 ImGui::SameLine();
4252 ImGui::SetNextItemWidth(60);
4253 ImGui::InputFloat(("##obj_orientation_z_" + std::to_string(id)).c_str(), &objects_dict[curr_obj_name].orientation.z);
4254 randomizePopup("obj_orientation_z_" + std::to_string(objects_dict[curr_obj_name].index), createTaggedPtr(&objects_dict[curr_obj_name].orientation.z, &objects_dict[curr_obj_name].is_dirty));
4255 randomizerParams("obj_orientation_z_" + std::to_string(objects_dict[curr_obj_name].index));
4256 ImGui::OpenPopupOnItemClick(("randomize_obj_orientation_z_" + std::to_string(objects_dict[curr_obj_name].index)).c_str(), ImGuiPopupFlags_MouseButtonRight);
4257 ImGui::SameLine();
4258 ImGui::Text("Object Orientation");
4259 if (prev_obj_orientation != objects_dict[curr_obj_name].orientation) {
4260 objects_dict[curr_obj_name].is_dirty = true;
4261 }
4262 if (objects_dict[current_obj].is_dirty && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemFocused()) {
4263 updateObject(current_obj);
4264 }
4265#endif
4266}
4267
4268void ProjectBuilder::radiationTab() {
4269#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_RADIATION_MODEL)
4270 // LOAD XML LIBRARY FILE
4271 ImGui::SetNextItemWidth(60);
4272 if (ImGui::Button("Load XML Library File")) {
4273 std::string new_xml_library_file = file_dialog();
4274 if (!new_xml_library_file.empty() && std::filesystem::exists(new_xml_library_file)) {
4275 if (xml_library_files.find(new_xml_library_file) == xml_library_files.end()) {
4276 xml_library_files.insert(new_xml_library_file);
4277 std::vector<std::string> current_spectra_file = get_xml_node_values(new_xml_library_file, "label", "globaldata_vec2");
4278 for (int i = 0; i < current_spectra_file.size(); i++) {
4279 possible_spectra.insert(current_spectra_file[i]);
4280 }
4281 }
4282 context->loadXML(new_xml_library_file.c_str());
4283 }
4284 }
4285 // ####### GLOBAL PROPERTIES ####### //
4286 ImGui::SetWindowFontScale(1.25f);
4287 ImGui::Text("Global Properties:");
4288 ImGui::SetWindowFontScale(1.0f);
4289 // ####### ENFORCE PERIODIC BOUNDARY CONDITION ####### //
4290 ImGui::Text("Enforce Periodic Boundary Condition:");
4291 ImGui::SameLine();
4292 bool prev_cond_x = enforce_periodic_boundary_x;
4293 ImGui::Checkbox("x###periodic_boundary_x", &enforce_periodic_boundary_x);
4294 ImGui::SameLine();
4295 bool prev_cond_y = enforce_periodic_boundary_y;
4296 ImGui::Checkbox("y###periodic_boundary_y", &enforce_periodic_boundary_y);
4297 if (prev_cond_x != enforce_periodic_boundary_x || prev_cond_y != enforce_periodic_boundary_y) {
4298 if (enforce_periodic_boundary_x && enforce_periodic_boundary_y)
4300 else if (enforce_periodic_boundary_x)
4302 else if (enforce_periodic_boundary_y)
4304 else
4306 }
4307 // ####### DIFFUSE EXTINCTION COEFFICIENT ####### //
4308 ImGui::SetNextItemWidth(60);
4309 float prev_value = diffuse_extinction_coeff;
4310 ImGui::InputFloat("Diffuse Extinction Coefficient", &diffuse_extinction_coeff);
4311 if (prev_value != diffuse_extinction_coeff) {
4312 context->setGlobalData("diffuse_extinction_coeff", diffuse_extinction_coeff);
4313 }
4314 randomizePopup("diffuse_extinction_coeff", createTaggedPtr(&diffuse_extinction_coeff));
4315 randomizerParams("diffuse_extinction_coeff");
4316 ImGui::OpenPopupOnItemClick("randomize_diffuse_extinction_coeff", ImGuiPopupFlags_MouseButtonRight);
4317 // ####### AIR TURBIDITY ####### //
4318 ImGui::SetNextItemWidth(60);
4319 prev_value = air_turbidity;
4320 ImGui::InputFloat("Air Turbidity", &air_turbidity);
4321 if (prev_value != air_turbidity) {
4322 if (air_turbidity > 0) {
4323 context->setGlobalData("air_turbidity", air_turbidity);
4324 } else if (air_turbidity < 0) { // try calibration
4325 if (context->doesTimeseriesVariableExist("net_radiation")) {
4326 air_turbidity = solarposition->calibrateTurbidityFromTimeseries("net_radiation");
4327 if (air_turbidity > 0 && air_turbidity < 1) {
4328 context->setGlobalData("air_turbidity", air_turbidity);
4329 }
4330 }
4331 }
4332 }
4333 randomizePopup("air_turbidity", createTaggedPtr(&air_turbidity));
4334 randomizerParams("air_turbidity");
4335 ImGui::OpenPopupOnItemClick("randomize_air_turbidity", ImGuiPopupFlags_MouseButtonRight);
4336 // ####### SOLAR DIRECT SPECTRUM ####### //
4337 ImGui::SetNextItemWidth(250);
4338 // ImGui::InputText("Solar Direct Spectrum", &solar_direct_spectrum);
4339 if (ImGui::BeginCombo("##combo_solar_direct_spectrum", solar_direct_spectrum.c_str())) {
4340 for (auto &spectra: possible_spectra) {
4341 bool is_solar_direct_spectrum_selected = (solar_direct_spectrum == spectra);
4342 if (ImGui::Selectable(spectra.c_str(), is_solar_direct_spectrum_selected))
4343 solar_direct_spectrum = spectra;
4344 if (is_solar_direct_spectrum_selected)
4345 ImGui::SetItemDefaultFocus();
4346 }
4347 ImGui::EndCombo();
4348 }
4349 ImGui::SameLine();
4350 ImGui::Text("Solar Direct Spectrum");
4351 // ####### BAND PROPERTIES ####### //
4352 ImGui::SetWindowFontScale(1.25f);
4353 ImGui::Text("Add Band:");
4354 ImGui::SetWindowFontScale(1.0f);
4355 // ####### ADD BAND ####### //
4356 toggle_button("##enable_wavelength", &enable_wavelength);
4357 ImGui::SameLine();
4358 if (enable_wavelength) {
4359 ImGui::Text("Wavelength Min:");
4360 ImGui::SameLine();
4361 ImGui::SetNextItemWidth(60);
4362 ImGui::InputFloat("##wavelength_min", &wavelength_min);
4363 ImGui::SameLine();
4364 ImGui::Text("Max:");
4365 ImGui::SameLine();
4366 ImGui::SetNextItemWidth(60);
4367 ImGui::InputFloat("##wavelength_max", &wavelength_max);
4368 } else {
4369 ImGui::Text("No Specified Wavelength");
4370 }
4371 //
4372 ImGui::Text("Label:");
4373 ImGui::SameLine();
4374 ImGui::SetNextItemWidth(100);
4375 ImGui::InputText("##new_band_label", &new_band_label);
4376 ImGui::SameLine();
4377 ImGui::Text("Emission:");
4378 ImGui::SameLine();
4379 ImGui::Checkbox("##enable_emission", &enable_emission);
4380 ImGui::SameLine();
4381 if (ImGui::Button("Add Band")) {
4382 if (enable_wavelength) {
4383 addBand(new_band_label, wavelength_min, wavelength_max, enable_emission);
4384 } else {
4385 addBand(new_band_label, enable_emission);
4386 bandlabels_set_wavelength.insert(new_band_label);
4387 }
4388 }
4389 // ####### BAND PROPERTIES ####### //
4390 ImGui::SetWindowFontScale(1.25f);
4391 ImGui::Text("Band Properties:");
4392 ImGui::SetWindowFontScale(1.0f);
4393 // ####### SELECT BAND ####### //
4394 if (ImGui::BeginCombo("##combo_current_band", current_band.c_str())) {
4395 for (std::string band: bandlabels_set) {
4396 bool is_current_band_selected = (current_band == band);
4397 if (ImGui::Selectable(band.c_str(), is_current_band_selected))
4398 current_band = band;
4399 if (is_current_band_selected)
4400 ImGui::SetItemDefaultFocus();
4401 }
4402 ImGui::EndCombo();
4403 }
4404 ImGui::SameLine();
4405 ImGui::Text("Select Band");
4406 // ####### DIRECT RAY COUNT ####### //
4407 int prev_direct_ray_count;
4408 ImGui::SetNextItemWidth(100);
4409 if (current_band == "All") {
4410 prev_direct_ray_count = direct_ray_count;
4411 ImGui::InputInt("Direct Ray Count", &direct_ray_count);
4412 randomizePopup("direct_ray_count", createTaggedPtr(&direct_ray_count));
4413 randomizerParams("direct_ray_count");
4414 ImGui::OpenPopupOnItemClick("randomize_direct_ray_count", ImGuiPopupFlags_MouseButtonRight);
4415 if (direct_ray_count != prev_direct_ray_count) {
4416 for (std::string band: bandlabels) {
4417 radiation->setDirectRayCount(band, direct_ray_count);
4418 direct_ray_count_dict[band] = direct_ray_count;
4419 }
4420 }
4421 } else {
4422 prev_direct_ray_count = direct_ray_count_dict[current_band];
4423 ImGui::InputInt("Direct Ray Count", &direct_ray_count_dict[current_band]);
4424 randomizePopup("direct_ray_count_" + current_band, createTaggedPtr(&direct_ray_count_dict[current_band]));
4425 randomizerParams("direct_ray_count_" + current_band);
4426 ImGui::OpenPopupOnItemClick(("randomize_direct_ray_count_" + current_band).c_str(), ImGuiPopupFlags_MouseButtonRight);
4427 if (direct_ray_count_dict[current_band] != prev_direct_ray_count) {
4428 radiation->setDirectRayCount(current_band, direct_ray_count_dict[current_band]);
4429 }
4430 }
4431 // ####### DIFFUSE RAY COUNT ####### //
4432 ImGui::SetNextItemWidth(100);
4433 int prev_diffuse_ray_count;
4434 if (current_band == "All") {
4435 prev_diffuse_ray_count = diffuse_ray_count;
4436 ImGui::InputInt("Diffuse Ray Count", &diffuse_ray_count);
4437 randomizePopup("diffuse_ray_count", createTaggedPtr(&diffuse_ray_count));
4438 randomizerParams("diffuse_ray_count");
4439 ImGui::OpenPopupOnItemClick("randomize_diffuse_ray_count", ImGuiPopupFlags_MouseButtonRight);
4440 if (diffuse_ray_count != prev_diffuse_ray_count) {
4441 for (std::string band: bandlabels) {
4442 radiation->setDiffuseRayCount(band, diffuse_ray_count);
4443 diffuse_ray_count_dict[band] = diffuse_ray_count;
4444 }
4445 }
4446 } else {
4447 prev_diffuse_ray_count = diffuse_ray_count_dict[current_band];
4448 ImGui::InputInt("Diffuse Ray Count", &diffuse_ray_count_dict[current_band]);
4449 randomizePopup("diffuse_ray_count_" + current_band, createTaggedPtr(&diffuse_ray_count_dict[current_band]));
4450 randomizerParams("diffuse_ray_count_" + current_band);
4451 ImGui::OpenPopupOnItemClick(("randomize_diffuse_ray_count_" + current_band).c_str(), ImGuiPopupFlags_MouseButtonRight);
4452 if (diffuse_ray_count_dict[current_band] != prev_diffuse_ray_count) {
4453 radiation->setDiffuseRayCount(current_band, diffuse_ray_count_dict[current_band]);
4454 }
4455 }
4456 // ####### SCATTERING DEPTH ####### //
4457 ImGui::SetNextItemWidth(100);
4458 int prev_scattering_depth;
4459 if (current_band == "All") {
4460 prev_scattering_depth = scattering_depth;
4461 ImGui::InputInt("Scattering Depth", &scattering_depth);
4462 randomizePopup("scattering_depth", createTaggedPtr(&scattering_depth));
4463 randomizerParams("scattering_depth");
4464 ImGui::OpenPopupOnItemClick("randomize_scattering_depth", ImGuiPopupFlags_MouseButtonRight);
4465 if (scattering_depth <= 0) {
4466 scattering_depth = prev_scattering_depth;
4467 }
4468 if (prev_scattering_depth != scattering_depth) {
4469 for (std::string band: bandlabels) {
4470 radiation->setScatteringDepth(band, scattering_depth);
4471 scattering_depth_dict[band] = scattering_depth;
4472 }
4473 }
4474 } else {
4475 prev_scattering_depth = scattering_depth_dict[current_band];
4476 ImGui::InputInt("Scattering Depth", &scattering_depth_dict[current_band]);
4477 randomizePopup("scattering_depth_" + current_band, createTaggedPtr(&scattering_depth_dict[current_band]));
4478 randomizerParams("scattering_depth_" + current_band);
4479 ImGui::OpenPopupOnItemClick(("randomize_scattering_depth_" + current_band).c_str(), ImGuiPopupFlags_MouseButtonRight);
4480 if (scattering_depth_dict[current_band] <= 0) { // scattering depth must be >0
4481 scattering_depth_dict[current_band] = prev_scattering_depth;
4482 }
4483 if (prev_scattering_depth != scattering_depth_dict[current_band]) {
4484 radiation->setScatteringDepth(current_band, scattering_depth_dict[current_band]);
4485 }
4486 }
4487 // ####### RADIATIVE PROPERTIES ####### //
4488 ImGui::SetWindowFontScale(1.25f);
4489 ImGui::Text("Radiative Properties:");
4490 ImGui::SetWindowFontScale(1.0f);
4491 ImGui::SetNextItemWidth(100);
4492 // ######### SELECT DATA GROUP ############//
4493 // if (ImGui::Button("Refresh###data_groups_refresh")) {
4494 // updatePrimitiveTypes();
4495 // updateDataGroups();
4496 // }
4497 // ImGui::SameLine();
4498 ImGui::SetNextItemWidth(150);
4499 if (ImGui::BeginCombo("##data_group_primitive", current_data_group.c_str())) {
4500 for (std::string data_group: data_groups_set) {
4501 bool is_data_group_selected = (current_data_group == data_group);
4502 if (ImGui::Selectable(data_group.c_str(), is_data_group_selected))
4503 current_data_group = data_group;
4504 if (is_data_group_selected)
4505 ImGui::SetItemDefaultFocus();
4506 }
4507 ImGui::EndCombo();
4508 }
4509 ImGui::SameLine();
4510 ImGui::SetNextItemWidth(100);
4511 ImGui::Text("Select Data Group");
4512 // default primitive data group
4513 // ######### SELECT PRIMITIVE ############//
4514 // if (ImGui::Button("Refresh")) {
4515 // updatePrimitiveTypes();
4516 // updateDataGroups();
4517 // }
4518 // ImGui::SameLine();
4519 ImGui::SetNextItemWidth(150);
4520 if (ImGui::BeginCombo("##combo_primitive", current_primitive.c_str())) {
4521 for (int m = 0; m < primitive_names.size(); m++) {
4522 bool is_primitive_selected = (current_primitive == primitive_names[m]);
4523 if (ImGui::Selectable(primitive_names[m].c_str(), is_primitive_selected))
4524 current_primitive = primitive_names[m];
4525 if (is_primitive_selected)
4526 ImGui::SetItemDefaultFocus();
4527 }
4528 ImGui::EndCombo();
4529 }
4530 ImGui::SameLine();
4531 ImGui::SetNextItemWidth(100);
4532 ImGui::Text("Select Primitive Type");
4533 if (current_data_group == "All") {
4534 // REFLECTIVITY
4535 ImGui::Text("Reflectivity:");
4536 std::string toggle_display_reflectivity = "Manual Entry";
4537 bool reflectivity_continuous = primitive_continuous[current_primitive][0];
4538 toggle_button("##reflectivity_toggle", &reflectivity_continuous);
4539 if (reflectivity_continuous != primitive_continuous[current_primitive][0]) {
4540 if (current_primitive == "All") {
4541 for (auto &prim_values: primitive_continuous) {
4542 primitive_continuous[prim_values.first][0] = reflectivity_continuous;
4543 }
4544 }
4545 primitive_continuous[current_primitive][0] = reflectivity_continuous;
4546 }
4547 if (primitive_continuous[current_primitive][0]) {
4548 toggle_display_reflectivity = "File Entry";
4549 }
4550 ImGui::SameLine();
4551 ImGui::SetNextItemWidth(250);
4552 if (!primitive_continuous[current_primitive][0]) {
4553 ImGui::Text("Select band:");
4554 ImGui::SameLine();
4555 ImGui::SetNextItemWidth(60);
4556 if (ImGui::BeginCombo("##combo_band_reflectivity", current_band_reflectivity.c_str())) {
4557 for (int n = 0; n < bandlabels.size(); n++) {
4558 bool is_band_selected = (current_band_reflectivity == bandlabels[n]);
4559 if (ImGui::Selectable(bandlabels[n].c_str(), is_band_selected))
4560 current_band_reflectivity = bandlabels[n];
4561 if (is_band_selected)
4562 ImGui::SetItemDefaultFocus();
4563 }
4564 ImGui::EndCombo();
4565 }
4566 ImGui::SameLine();
4567 ImGui::Text("Enter value:");
4568 ImGui::SameLine();
4569 ImGui::SetNextItemWidth(80);
4570 if (current_primitive == "All") {
4571 float prev_reflectivity = reflectivity;
4572 ImGui::InputFloat("##reflectivity_all", &reflectivity);
4573 if (reflectivity != prev_reflectivity) {
4574 for (auto &prim_values: primitive_values[current_band_reflectivity]) {
4575 primitive_values[current_band_reflectivity][prim_values.first][0] = reflectivity;
4576 }
4577 }
4578 } else {
4579 ImGui::InputFloat("##reflectivity", &primitive_values[current_band_reflectivity][current_primitive][0]);
4580 }
4581 } else {
4582 std::string reflectivity_prev = primitive_spectra[current_primitive][0];
4583 if (ImGui::BeginCombo("##reflectivity_combo_all", reflectivity_prev.c_str())) {
4584 for (auto &spectra: possible_spectra) {
4585 bool is_spectra_selected = (primitive_spectra[current_primitive][0] == spectra);
4586 if (ImGui::Selectable(spectra.c_str(), is_spectra_selected))
4587 primitive_spectra[current_primitive][0] = spectra;
4588 if (is_spectra_selected)
4589 ImGui::SetItemDefaultFocus();
4590 }
4591 ImGui::EndCombo();
4592 }
4593 if (current_primitive == "All" && reflectivity_prev != primitive_spectra[current_primitive][0]) {
4594 for (auto &prim_spectrum: primitive_spectra) {
4595 primitive_spectra[prim_spectrum.first][0] = primitive_spectra[current_primitive][0];
4596 }
4597 }
4598 }
4599 ImGui::SameLine();
4600 ImGui::Text("%s", toggle_display_reflectivity.c_str());
4601 // TRANSMISSIVITY
4602 ImGui::Text("Transmissivity:");
4603 std::string toggle_display_transmissivity = "Manual Entry";
4604 bool transmissivity_continuous = primitive_continuous[current_primitive][1];
4605 toggle_button("##transmissivity_toggle", &transmissivity_continuous);
4606 if (transmissivity_continuous != primitive_continuous[current_primitive][1]) {
4607 if (current_primitive == "All") {
4608 for (auto &prim_values: primitive_continuous) {
4609 primitive_continuous[prim_values.first][1] = transmissivity_continuous;
4610 }
4611 }
4612 primitive_continuous[current_primitive][1] = transmissivity_continuous;
4613 }
4614 if (primitive_continuous[current_primitive][1]) {
4615 toggle_display_transmissivity = "File Entry";
4616 }
4617 ImGui::SameLine();
4618 ImGui::SetNextItemWidth(250);
4619 if (!primitive_continuous[current_primitive][1]) {
4620 ImGui::Text("Select band:");
4621 ImGui::SameLine();
4622 ImGui::SetNextItemWidth(60);
4623 if (ImGui::BeginCombo("##combo_band_transmissivity", current_band_transmissivity.c_str())) {
4624 for (int n = 0; n < bandlabels.size(); n++) {
4625 bool is_band_selected = (current_band_transmissivity == bandlabels[n]);
4626 if (ImGui::Selectable(bandlabels[n].c_str(), is_band_selected))
4627 current_band_transmissivity = bandlabels[n];
4628 if (is_band_selected)
4629 ImGui::SetItemDefaultFocus();
4630 }
4631 ImGui::EndCombo();
4632 }
4633 ImGui::SameLine();
4634 ImGui::Text("Enter value:");
4635 ImGui::SameLine();
4636 ImGui::SetNextItemWidth(80);
4637 if (current_primitive == "All") {
4638 float prev_transmissivity = transmissivity;
4639 ImGui::InputFloat("##transmissivity_all", &transmissivity);
4640 if (transmissivity != prev_transmissivity) {
4641 for (auto &prim_values: primitive_values[current_band_transmissivity]) {
4642 primitive_values[current_band_transmissivity][prim_values.first][1] = transmissivity;
4643 }
4644 }
4645 } else {
4646 ImGui::InputFloat("##transmissivity", &primitive_values[current_band_transmissivity][current_primitive][1]);
4647 }
4648 } else {
4649 std::string transmissivity_prev = primitive_spectra[current_primitive][1];
4650 if (ImGui::BeginCombo("##transmissivity_combo", transmissivity_prev.c_str())) {
4651 for (auto &spectra: possible_spectra) {
4652 bool is_spectra_selected = (primitive_spectra[current_primitive][1] == spectra);
4653 if (ImGui::Selectable(spectra.c_str(), is_spectra_selected))
4654 primitive_spectra[current_primitive][1] = spectra;
4655 if (is_spectra_selected)
4656 ImGui::SetItemDefaultFocus();
4657 }
4658 ImGui::EndCombo();
4659 }
4660 if (current_primitive == "All" && transmissivity_prev != primitive_spectra[current_primitive][1]) {
4661 for (auto &prim_spectrum: primitive_spectra) {
4662 primitive_spectra[prim_spectrum.first][1] = primitive_spectra[current_primitive][1];
4663 }
4664 }
4665 }
4666 ImGui::SameLine();
4667 ImGui::Text("%s", toggle_display_transmissivity.c_str());
4668 // EMISSIVITY
4669 ImGui::Text("Emissivity:");
4670 // ImGui::SetNextItemWidth(250);
4671 // ImGui::Text("");
4672 ImGui::Dummy(ImVec2(35.f, 0.f));
4673 ImGui::SameLine();
4674 ImGui::Text("Select band:");
4675 ImGui::SameLine();
4676 ImGui::SetNextItemWidth(60);
4677 if (ImGui::BeginCombo("##combo_band_emissivity", current_band_emissivity.c_str())) {
4678 for (std::string band: bandlabels_set_emissivity) {
4679 bool is_band_selected = (current_band_emissivity == band);
4680 if (ImGui::Selectable(band.c_str(), is_band_selected))
4681 current_band_emissivity = band;
4682 if (is_band_selected)
4683 ImGui::SetItemDefaultFocus();
4684 }
4685 ImGui::EndCombo();
4686 }
4687 ImGui::SameLine();
4688 ImGui::Text("Enter value:");
4689 ImGui::SameLine();
4690 ImGui::SetNextItemWidth(80);
4691 if (current_primitive == "All") {
4692 float prev_emissivity = emissivity;
4693 ImGui::InputFloat("##emissivity_all", &emissivity);
4694 if (emissivity != prev_emissivity) {
4695 for (auto &prim_values: primitive_values[current_band_emissivity]) {
4696 primitive_values[current_band_emissivity][prim_values.first][2] = emissivity;
4697 }
4698 }
4699 } else {
4700 ImGui::InputFloat("##emissivity", &primitive_values[current_band_emissivity][current_primitive][2]);
4701 }
4702 ImGui::SameLine();
4703 ImGui::Text("Manual Entry");
4704 } else { // specific data group
4705 // REFLECTIVITY
4706 ImGui::Text("Reflectivity:");
4707 std::string toggle_display_reflectivity = "Manual Entry";
4708 bool reflectivity_continuous = primitive_continuous_dict[current_data_group][current_primitive][0];
4709 toggle_button("##reflectivity_toggle", &reflectivity_continuous);
4710 if (reflectivity_continuous != primitive_continuous_dict[current_data_group][current_primitive][0]) {
4711 if (current_primitive == "All") {
4712 for (auto &prim_values: primitive_continuous_dict[current_data_group]) {
4713 primitive_continuous_dict[current_data_group][prim_values.first][0] = reflectivity_continuous;
4714 }
4715 }
4716 primitive_continuous_dict[current_data_group][current_primitive][0] = reflectivity_continuous;
4717 }
4718 if (primitive_continuous_dict[current_data_group][current_primitive][0]) {
4719 toggle_display_reflectivity = "File Entry";
4720 }
4721 ImGui::SameLine();
4722 ImGui::SetNextItemWidth(250);
4723 if (!primitive_continuous_dict[current_data_group][current_primitive][0]) {
4724 ImGui::Text("Select band:");
4725 ImGui::SameLine();
4726 ImGui::SetNextItemWidth(60);
4727 if (ImGui::BeginCombo("##combo_band_reflectivity", current_band_reflectivity.c_str())) {
4728 for (int n = 0; n < bandlabels.size(); n++) {
4729 bool is_band_selected = (current_band_reflectivity == bandlabels[n]);
4730 if (ImGui::Selectable(bandlabels[n].c_str(), is_band_selected))
4731 current_band_reflectivity = bandlabels[n];
4732 if (is_band_selected)
4733 ImGui::SetItemDefaultFocus();
4734 }
4735 ImGui::EndCombo();
4736 }
4737 ImGui::SameLine();
4738 ImGui::Text("Enter value:");
4739 ImGui::SameLine();
4740 ImGui::SetNextItemWidth(80);
4741 if (current_primitive == "All") {
4742 float prev_reflectivity = reflectivity;
4743 ImGui::InputFloat("##reflectivity_all", &reflectivity);
4744 if (reflectivity != prev_reflectivity) {
4745 for (auto &prim_values: primitive_values_dict[current_data_group][current_band_reflectivity]) {
4746 primitive_values_dict[current_data_group][current_band_reflectivity][prim_values.first][0] = reflectivity;
4747 }
4748 }
4749 } else {
4750 ImGui::InputFloat("##reflectivity", &primitive_values_dict[current_data_group][current_band_reflectivity][current_primitive][0]);
4751 }
4752 } else {
4753 std::string reflectivity_prev = primitive_spectra_dict[current_data_group][current_primitive][0];
4754 if (ImGui::BeginCombo("##reflectivity_combo", reflectivity_prev.c_str())) {
4755 for (auto &spectra: possible_spectra) {
4756 bool is_spectra_selected = (primitive_spectra_dict[current_data_group][current_primitive][0] == spectra);
4757 if (ImGui::Selectable(spectra.c_str(), is_spectra_selected))
4758 primitive_spectra_dict[current_data_group][current_primitive][0] = spectra;
4759 if (is_spectra_selected)
4760 ImGui::SetItemDefaultFocus();
4761 }
4762 ImGui::EndCombo();
4763 }
4764 if (current_primitive == "All" && reflectivity_prev != primitive_spectra_dict[current_data_group][current_primitive][0]) {
4765 for (auto &prim_spectrum: primitive_spectra_dict[current_data_group]) {
4766 primitive_spectra_dict[current_data_group][prim_spectrum.first][0] = primitive_spectra_dict[current_data_group][current_primitive][0];
4767 }
4768 }
4769 }
4770 ImGui::SameLine();
4771 ImGui::TextUnformatted("%s", toggle_display_reflectivity.c_str());
4772 // TRANSMISSIVITY
4773 ImGui::Text("Transmissivity:");
4774 std::string toggle_display_transmissivity = "Manual Entry";
4775 bool transmissivity_continuous = primitive_continuous_dict[current_data_group][current_primitive][1];
4776 toggle_button("##transmissivity_toggle", &transmissivity_continuous);
4777 if (transmissivity_continuous != primitive_continuous_dict[current_data_group][current_primitive][1]) {
4778 if (current_primitive == "All") {
4779 for (auto &prim_values: primitive_continuous_dict[current_data_group]) {
4780 primitive_continuous_dict[current_data_group][prim_values.first][1] = transmissivity_continuous;
4781 }
4782 }
4783 primitive_continuous_dict[current_data_group][current_primitive][1] = transmissivity_continuous;
4784 }
4785 if (primitive_continuous_dict[current_data_group][current_primitive][1]) {
4786 toggle_display_transmissivity = "File Entry";
4787 }
4788 ImGui::SameLine();
4789 ImGui::SetNextItemWidth(250);
4790 if (!primitive_continuous_dict[current_data_group][current_primitive][1]) {
4791 ImGui::Text("Select band:");
4792 ImGui::SameLine();
4793 ImGui::SetNextItemWidth(60);
4794 if (ImGui::BeginCombo("##combo_band_transmissivity", current_band_transmissivity.c_str())) {
4795 for (int n = 0; n < bandlabels.size(); n++) {
4796 bool is_band_selected = (current_band_transmissivity == bandlabels[n]);
4797 if (ImGui::Selectable(bandlabels[n].c_str(), is_band_selected))
4798 current_band_transmissivity = bandlabels[n];
4799 if (is_band_selected)
4800 ImGui::SetItemDefaultFocus();
4801 }
4802 ImGui::EndCombo();
4803 }
4804 ImGui::SameLine();
4805 ImGui::Text("Enter value:");
4806 ImGui::SameLine();
4807 ImGui::SetNextItemWidth(80);
4808 if (current_primitive == "All") {
4809 float prev_transmissivity = transmissivity;
4810 ImGui::InputFloat("##transmissivity_all", &transmissivity);
4811 if (transmissivity != prev_transmissivity) {
4812 for (auto &prim_values: primitive_values_dict[current_data_group][current_band_transmissivity]) {
4813 primitive_values_dict[current_data_group][current_band_transmissivity][prim_values.first][1] = transmissivity;
4814 }
4815 }
4816 } else {
4817 ImGui::InputFloat("##transmissivity", &primitive_values_dict[current_data_group][current_band_transmissivity][current_primitive][1]);
4818 }
4819 } else {
4820 std::string transmissivity_prev = primitive_spectra_dict[current_data_group][current_primitive][1];
4821 if (ImGui::BeginCombo("##transmissivity_combo", transmissivity_prev.c_str())) {
4822 for (auto &spectra: possible_spectra) {
4823 bool is_spectra_selected = (primitive_spectra_dict[current_data_group][current_primitive][1] == spectra);
4824 if (ImGui::Selectable(spectra.c_str(), is_spectra_selected))
4825 primitive_spectra_dict[current_data_group][current_primitive][1] = spectra;
4826 if (is_spectra_selected)
4827 ImGui::SetItemDefaultFocus();
4828 }
4829 ImGui::EndCombo();
4830 }
4831 if (current_primitive == "All" && transmissivity_prev != primitive_spectra_dict[current_data_group][current_primitive][1]) {
4832 for (auto &prim_spectrum: primitive_spectra_dict[current_data_group]) {
4833 primitive_spectra_dict[current_data_group][prim_spectrum.first][1] = primitive_spectra_dict[current_data_group][current_primitive][1];
4834 }
4835 }
4836 }
4837 ImGui::SameLine();
4838 ImGui::TextUnformatted("%s", toggle_display_transmissivity.c_str());
4839 // EMISSIVITY
4840 ImGui::Text("Emissivity:");
4841 // ImGui::SetNextItemWidth(250);
4842 // ImGui::Text("");
4843 ImGui::Dummy(ImVec2(35.f, 0.f));
4844 ImGui::SameLine();
4845 ImGui::Text("Select band:");
4846 ImGui::SameLine();
4847 ImGui::SetNextItemWidth(60);
4848 if (ImGui::BeginCombo("##combo_band_emissivity", current_band_emissivity.c_str())) {
4849 for (std::string band: bandlabels_set_emissivity) {
4850 bool is_band_selected = (current_band_emissivity == band);
4851 if (ImGui::Selectable(band.c_str(), is_band_selected))
4852 current_band_emissivity = band;
4853 if (is_band_selected)
4854 ImGui::SetItemDefaultFocus();
4855 }
4856 ImGui::EndCombo();
4857 }
4858 ImGui::SameLine();
4859 ImGui::Text("Enter value:");
4860 ImGui::SameLine();
4861 ImGui::SetNextItemWidth(80);
4862 if (current_primitive == "All") {
4863 float prev_emissivity = emissivity;
4864 ImGui::InputFloat("##emissivity_all", &emissivity);
4865 if (emissivity != prev_emissivity) {
4866 for (auto &prim_values: primitive_values_dict[current_data_group][current_band_emissivity]) {
4867 primitive_values_dict[current_data_group][current_band_emissivity][prim_values.first][2] = emissivity;
4868 }
4869 }
4870 } else {
4871 ImGui::InputFloat("##emissivity", &primitive_values_dict[current_data_group][current_band_emissivity][current_primitive][2]);
4872 }
4873 ImGui::SameLine();
4874 ImGui::Text("Manual Entry");
4875 }
4876 ImGui::NewLine();
4877 if (ImGui::Button("Run Radiation")) {
4878 const char *font_name = "LCD";
4879 visualizer->addTextboxByCenter("LOADING...", vec3(.5, .5, 0), make_SphericalCoord(0, 0), RGB::red, 40, font_name, Visualizer::COORDINATES_WINDOW_NORMALIZED);
4881 runRadiation();
4883 }
4884#endif
4885}
4886
4887
4888void ProjectBuilder::rigTab() {
4889#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_RADIATION_MODEL)
4890 std::string current_cam_position = "0";
4891 if (ImGui::BeginCombo("##rig_combo", current_rig.c_str())) {
4892 for (auto rig_label: rig_labels_set) {
4893 bool is_rig_selected = (current_rig == rig_label);
4894 if (ImGui::Selectable(rig_label.c_str(), is_rig_selected))
4895 current_rig = rig_label;
4896 current_cam_position = "0";
4897 if (is_rig_selected)
4898 ImGui::SetItemDefaultFocus();
4899 }
4900 ImGui::EndCombo();
4901 }
4902 ImGui::SameLine();
4903 if (ImGui::Button("Add Rig")) {
4904 std::string default_rig_label = "rig";
4905 std::string new_rig_label = "rig_0";
4906 int count = 0;
4907 while (rig_dict.find(new_rig_label) != rig_dict.end()) {
4908 count++;
4909 new_rig_label = default_rig_label + "_" + std::to_string(count);
4910 }
4911 addRig(new_rig_label);
4912 }
4913 if (!current_rig.empty()) {
4914 // ##### UPDATE RIG ######//
4915 // if (ImGui::Button("Update Rig")){
4916 // updateRigs();
4917 // }
4918 // ImGui::SameLine();
4919 if (ImGui::Button("Delete Rig")) {
4920 deleteRig(current_rig);
4921 }
4922 // ##### RIG NAME ######//
4923 ImGui::SetNextItemWidth(100);
4924 std::string prev_rig_name = rig_labels[rig_dict[current_rig]];
4925 ImGui::InputText("##rig_name", &rig_labels[rig_dict[current_rig]]);
4926 if (rig_labels[rig_dict[current_rig]] != prev_rig_name && rig_dict.find(rig_labels[rig_dict[current_rig]]) == rig_dict.end() && !rig_labels[rig_dict[current_rig]].empty()) {
4927 int temp = rig_dict[current_rig];
4928 current_rig = rig_labels[rig_dict[current_rig]];
4929 std::map<std::string, int>::iterator current_rig_iter = rig_dict.find(prev_rig_name);
4930 if (current_rig_iter != rig_dict.end()) {
4931 rig_dict.erase(current_rig_iter);
4932 }
4933 rig_dict[current_rig] = temp;
4934 rig_labels_set.erase(prev_rig_name);
4935 rig_labels_set.insert(rig_labels[rig_dict[current_rig]]);
4936
4937 std::string new_name = rig_labels[rig_dict[current_rig]];
4938 rig renamed_rig = rig_dict_.at(prev_rig_name);
4939 rig_dict_.erase(prev_rig_name);
4940 rig_dict_.insert({new_name, renamed_rig});
4941 } else {
4942 rig_labels[rig_dict[current_rig]] = prev_rig_name;
4943 }
4944 ImGui::SameLine();
4945 ImGui::Text("Rig Name");
4946 // ####### WRITE DEPTH ####### //
4947 ImGui::Text("Write:");
4948 ImGui::SameLine();
4949 int rig_index = rig_dict[current_rig];
4950 if (rig_index >= write_depth.size()) {
4951 helios_runtime_error("ERROR (ProjectBuilder::rigTab): rig_dict[" + current_rig + "] = " + std::to_string(rig_index) + " is out of bounds for write_depth vector of size " + std::to_string(write_depth.size()));
4952 }
4953 bool write_depth_ = write_depth[rig_index];
4954 ImGui::Checkbox("Depth Images", &write_depth_);
4955 write_depth[rig_dict[current_rig]] = write_depth_;
4956 ImGui::SameLine();
4957 bool write_norm_depth_ = write_norm_depth[rig_dict[current_rig]];
4958 ImGui::Checkbox("Norm Depth Images", &write_norm_depth_);
4959 write_norm_depth[rig_dict[current_rig]] = write_norm_depth_;
4960 ImGui::SameLine();
4961 bool write_segmentation_ = write_segmentation_mask[rig_dict[current_rig]];
4962 ImGui::Checkbox("Segmentation Masks", &write_segmentation_);
4963 write_segmentation_mask[rig_dict[current_rig]] = write_segmentation_;
4964 // ####### BOUNDING BOXES ####### //
4965 if (ImGui::BeginPopup("multi_select_popup")) {
4966 for (auto &box_pair: bounding_boxes) {
4967 ImGui::Selectable(box_pair.first.c_str(), &box_pair.second, ImGuiSelectableFlags_DontClosePopups);
4968 }
4969 ImGui::EndPopup();
4970 }
4971 if (ImGui::Button("Select Labeled Objects")) {
4972 ImGui::OpenPopup("multi_select_popup");
4973 }
4974 ImGui::SameLine();
4975 if (ImGui::Button("Refresh List")) {
4976 refreshBoundingBoxObjectList();
4977 }
4978 // ImGui::OpenPopupOnItemClick(("rig_position_noise_" + std::to_string(rig_dict[current_rig])).c_str(), ImGuiPopupFlags_MouseButtonLeft);
4979 // Display selected items
4980 ImGui::Text("Objects:");
4981 int idx = 0;
4982 for (auto &box_pair: bounding_boxes) {
4983 if (box_pair.second) {
4984 ImGui::SameLine(), ImGui::Text("%i. %s", idx, box_pair.first.c_str());
4985 idx++;
4986 }
4987 }
4988 // ####### RIG COLOR ####### //
4989 float col[3];
4990 col[0] = rig_colors[rig_dict[current_rig]].r;
4991 col[1] = rig_colors[rig_dict[current_rig]].g;
4992 col[2] = rig_colors[rig_dict[current_rig]].b;
4993 ImGui::ColorEdit3("##rig_color_edit", col);
4994 updateColor(current_rig, "rig", col);
4995 ImGui::SameLine();
4996 ImGui::Text("Rig Color");
4997 // ####### CAMERA LABEL ####### //
4998 /* SINGLE CAMERA VERSION
4999 ImGui::SetNextItemWidth(60);
5000 // ImGui::InputText("Camera Label", &camera_labels[rig_dict[(std::string) current_rig]]);
5001 if (ImGui::BeginCombo("##cam_label_combo", camera_labels[rig_dict[(std::string) current_rig]].c_str())){
5002 for (int n = 0; n < camera_names.size(); n++){
5003 bool is_cam_label_selected = (camera_labels[rig_dict[(std::string) current_rig]] == camera_names[n]); // You can store your selection however you want, outside or inside your objects
5004 if (ImGui::Selectable(camera_names[n].c_str(), is_cam_label_selected)){
5005 camera_labels[rig_dict[(std::string) current_rig]] = camera_names[n];
5006 }
5007 if (is_cam_label_selected)
5008 ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support)
5009 }
5010 ImGui::EndCombo();
5011 }
5012 ImGui::SameLine();
5013 ImGui::Text("Camera Label");
5014 ImGui::EndTabItem();
5015 */
5016 // ####### CAMERA CHECKBOX ####### //
5017 ImGui::Text("Cameras:");
5018 for (int i = 0; i < camera_names.size(); i++) {
5019 std::string &camera_name = camera_names[i];
5020
5021 ImGui::SetNextItemWidth(60);
5022
5023 std::set curr_set = rig_camera_labels[rig_dict[current_rig]];
5024 // if (i % 3 != 0){
5025 // ImGui::SameLine();
5026 // }
5027 bool isCameraSelected = curr_set.find(camera_name) != curr_set.end();
5028 ImGui::PushID(i);
5029 if (ImGui::Checkbox(camera_name.c_str(), &isCameraSelected)) {
5030 if (isCameraSelected) {
5031 rig_camera_labels[rig_dict[current_rig]].insert(camera_name);
5032 } else {
5033 rig_camera_labels[rig_dict[current_rig]].erase(camera_name);
5034 }
5035 }
5036 ImGui::PopID();
5037 }
5038 // ####### LIGHT CHECKBOX ####### //
5039 ImGui::Text("Lights:");
5040 for (int i = 0; i < light_names.size(); i++) {
5041 std::string &light_name = light_names[i];
5042
5043 ImGui::SetNextItemWidth(60);
5044
5045 std::set curr_rig_light = rig_light_labels[rig_dict[current_rig]];
5046 bool isLightSelected = curr_rig_light.find(light_name) != curr_rig_light.end();
5047 ImGui::PushID(i);
5048 if (ImGui::Checkbox(light_name.c_str(), &isLightSelected)) {
5049 if (isLightSelected) {
5050 rig_light_labels[rig_dict[current_rig]].insert(light_name);
5051 } else {
5052 rig_light_labels[rig_dict[current_rig]].erase(light_name);
5053 }
5054 }
5055 ImGui::PopID();
5056 }
5057 // ####### ADD KEYPOINT ####### //
5058 std::stringstream cam_pos_value;
5059 cam_pos_value << current_cam_position.c_str();
5060 int current_cam_position_;
5061 cam_pos_value >> current_cam_position_;
5062 current_keypoint = std::to_string(keypoint_frames[rig_dict[current_rig]][current_cam_position_]);
5063 std::string modified_current_keypoint = std::to_string(keypoint_frames[rig_dict[current_rig]][current_cam_position_] + 1); // 1-indexed value
5064 if (ImGui::BeginCombo("##cam_combo", modified_current_keypoint.c_str())) {
5065 for (int n = 1; n <= camera_position_vec[rig_dict[current_rig]].size(); n++) {
5066 std::string select_cam_position = std::to_string(n - 1);
5067 std::string selected_keypoint = std::to_string(keypoint_frames[rig_dict[current_rig]][n - 1]);
5068 bool is_pos_selected = (current_cam_position == select_cam_position);
5069 std::string modified_selected_keypoint = std::to_string(keypoint_frames[rig_dict[current_rig]][n - 1] + 1); // 1-indexed value
5070 if (ImGui::Selectable(modified_selected_keypoint.c_str(), is_pos_selected)) {
5071 current_cam_position = std::to_string(n - 1);
5072 }
5073 if (is_pos_selected)
5074 ImGui::SetItemDefaultFocus();
5075 }
5076 ImGui::EndCombo();
5077 }
5078 cam_pos_value << current_cam_position.c_str();
5079 cam_pos_value >> current_cam_position_;
5080 ImGui::SameLine();
5081 if (ImGui::Button("Add Keypoint")) {
5082 camera_position_vec[rig_dict[current_rig]].push_back(camera_position_vec[rig_dict[current_rig]][current_cam_position_]);
5083 camera_lookat_vec[rig_dict[current_rig]].push_back(camera_lookat_vec[rig_dict[current_rig]][current_cam_position_]);
5084 keypoint_frames[rig_dict[current_rig]].push_back(keypoint_frames[rig_dict[current_rig]].back() + 1);
5085 is_dirty = true;
5086 }
5087 // ####### KEYPOINT FRAME ####### //
5088 ImGui::SetNextItemWidth(80);
5089 int modified_keypoint_frame = keypoint_frames[rig_dict[current_rig]][current_cam_position_] + 1; // 1-indexed value
5090 ImGui::InputInt("Keypoint Frame", &modified_keypoint_frame);
5091 if (modified_keypoint_frame != keypoint_frames[rig_dict[current_rig]][current_cam_position_] + 1) {
5092 keypoint_frames[rig_dict[current_rig]][current_cam_position_] = modified_keypoint_frame - 1;
5093 }
5094 // ####### CAMERA POSITION ####### //
5095 vec3 prev_rig_position_ = camera_position_vec[rig_dict[current_rig]][current_cam_position_];
5096 ImGui::SetNextItemWidth(60);
5097 ImGui::InputFloat("##camera_position_x", &camera_position_vec[rig_dict[current_rig]][current_cam_position_].x);
5098 randomizePopup("camera_position_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_position_vec[rig_dict[current_rig]][current_cam_position_].x));
5099 randomizerParams("camera_position_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5100 ImGui::OpenPopupOnItemClick(("randomize_camera_position_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5101 ImGui::SameLine();
5102 ImGui::SetNextItemWidth(60);
5103 ImGui::InputFloat("##camera_position_y", &camera_position_vec[rig_dict[current_rig]][current_cam_position_].y);
5104 randomizePopup("camera_position_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_position_vec[rig_dict[current_rig]][current_cam_position_].y));
5105 randomizerParams("camera_position_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5106 ImGui::OpenPopupOnItemClick(("randomize_camera_position_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5107 ImGui::SameLine();
5108 ImGui::SetNextItemWidth(60);
5109 ImGui::InputFloat("##camera_position_z", &camera_position_vec[rig_dict[current_rig]][current_cam_position_].z);
5110 randomizePopup("camera_position_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_position_vec[rig_dict[current_rig]][current_cam_position_].z));
5111 randomizerParams("camera_position_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5112 ImGui::OpenPopupOnItemClick(("randomize_camera_position_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5113 ImGui::SameLine();
5114 ImGui::Text("Rig Position");
5115 ImGui::SameLine();
5116 ImGui::Button("Add Noise###position");
5117 noisePopup("rig_position_noise_" + std::to_string(rig_dict[current_rig]), rig_lookat_noise[rig_dict[current_rig]]);
5118 ImGui::OpenPopupOnItemClick(("rig_position_noise_" + std::to_string(rig_dict[current_rig])).c_str(), ImGuiPopupFlags_MouseButtonLeft);
5119 // ####### CAMERA LOOKAT ####### //
5120 vec3 prev_rig_lookat_ = camera_lookat_vec[rig_dict[current_rig]][current_cam_position_];
5121 ImGui::SetNextItemWidth(60);
5122 ImGui::InputFloat("##camera_lookat_x", &camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].x);
5123 randomizePopup("camera_lookat_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].x));
5124 randomizerParams("camera_lookat_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5125 ImGui::OpenPopupOnItemClick(("randomize_camera_lookat_x_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5126 ImGui::SameLine();
5127 ImGui::SetNextItemWidth(60);
5128 ImGui::InputFloat("##camera_lookat_y", &camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].y);
5129 randomizePopup("camera_lookat_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].y));
5130 randomizerParams("camera_lookat_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5131 ImGui::OpenPopupOnItemClick(("randomize_camera_lookat_y_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5132 ImGui::SameLine();
5133 ImGui::SetNextItemWidth(60);
5134 ImGui::InputFloat("##camera_lookat_z", &camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].z);
5135 randomizePopup("camera_lookat_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_), createTaggedPtr(&camera_lookat_vec[rig_dict[current_rig]][current_cam_position_].z));
5136 randomizerParams("camera_lookat_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_));
5137 ImGui::OpenPopupOnItemClick(("randomize_camera_lookat_z_" + std::to_string(rig_dict[current_rig]) + std::to_string(current_cam_position_)).c_str(), ImGuiPopupFlags_MouseButtonRight);
5138 ImGui::SameLine();
5139 ImGui::Text("Rig Lookat");
5140 ImGui::SameLine();
5141 ImGui::Button("Add Noise###lookat");
5142 noisePopup("rig_lookat_noise_" + std::to_string(rig_dict[current_rig]), rig_lookat_noise[rig_dict[current_rig]]);
5143 ImGui::OpenPopupOnItemClick(("rig_lookat_noise_" + std::to_string(rig_dict[current_rig])).c_str(), ImGuiPopupFlags_MouseButtonLeft);
5144 // ####### NUMBER OF IMAGES ####### //
5145 ImGui::SetNextItemWidth(80);
5146 ImGui::InputInt("Total Number of Frames", &num_images_vec[rig_dict[current_rig]]);
5147 num_images_vec[rig_dict[current_rig]] = std::max(num_images_vec[rig_dict[current_rig]], *std::max_element(keypoint_frames[rig_dict[current_rig]].begin(), keypoint_frames[rig_dict[(std::string) current_rig]].end()) + 1);
5148
5149 if (prev_rig_position_ != camera_position_vec[rig_dict[current_rig]][current_cam_position_] || prev_rig_lookat_ != camera_lookat_vec[rig_dict[current_rig]][current_cam_position_]) {
5150 updateRigs();
5151 }
5152
5153 ImGui::NewLine();
5154 if (ImGui::Button("Record Images")) {
5155 if (band_group_names.empty()) {
5156 std::cout << "At least 1 band group (a group of 1 or 3 bands) must be defined to record images." << std::endl;
5157 } else {
5158 // Update reflectivity, transmissivity, & emissivity for each band / primitive_type
5159 const char *font_name = "LCD";
5160 visualizer->addTextboxByCenter("LOADING...", vec3(.5, .5, 0), make_SphericalCoord(0, 0), RGB::red, 40, font_name, Visualizer::COORDINATES_WINDOW_NORMALIZED);
5162 updatePrimitiveTypes();
5163 updateSpectra();
5164 updateCameras();
5165 try {
5166 record();
5167 } catch (const std::runtime_error &e) {
5168 std::cerr << "Record failed due to exception: " << e.what() << std::endl;
5170 }
5171 }
5172 }
5173 }
5174#endif
5175}
5176
5177
5178void ProjectBuilder::rigTab(std::string curr_rig_name, int id) {
5179#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_RADIATION_MODEL)
5180 ImGui::SetNextItemWidth(100);
5181 std::string prev_rig_name = rig_labels[rig_dict[curr_rig_name]];
5182 ImGui::InputText("##rig_name", &rig_labels[rig_dict[curr_rig_name]]);
5183 if (rig_labels[rig_dict[curr_rig_name]] != prev_rig_name && rig_labels_set.find(rig_labels[rig_dict[curr_rig_name]]) == rig_labels_set.end() && !rig_labels[rig_dict[curr_rig_name]].empty()) {
5184 rig_labels_set.erase(prev_rig_name);
5185 int temp = rig_dict[curr_rig_name];
5186 rig_labels_set.insert(rig_labels[temp]);
5187 curr_rig_name = rig_labels[rig_dict[curr_rig_name]];
5188 std::map<std::string, int>::iterator current_rig_iter = rig_dict.find(prev_rig_name);
5189 if (current_rig_iter != rig_dict.end()) {
5190 rig_dict.erase(current_rig_iter);
5191 }
5192 rig_dict[curr_rig_name] = temp;
5193
5194 rig_labels_set.erase(prev_rig_name);
5195 rig_labels_set.insert(rig_labels[rig_dict[curr_rig_name]]);
5196 } else {
5197 rig_labels[rig_dict[curr_rig_name]] = prev_rig_name;
5198 }
5199 ImGui::SameLine();
5200 ImGui::Text("Rig Name");
5201 int current_cam_position_ = 0; // TODO: make this dynamic
5202 // ####### CAMERA POSITION ####### //
5203 vec3 prev_rig_position = vec3(camera_position_vec[rig_dict[curr_rig_name]][current_cam_position_]);
5204 ImGui::SetNextItemWidth(60);
5205 ImGui::InputFloat("##camera_position_x", &camera_position_vec[rig_dict[curr_rig_name]][current_cam_position_].x);
5206 ImGui::SameLine();
5207 ImGui::SetNextItemWidth(60);
5208 ImGui::InputFloat("##camera_position_y", &camera_position_vec[rig_dict[curr_rig_name]][current_cam_position_].y);
5209 ImGui::SameLine();
5210 ImGui::SetNextItemWidth(60);
5211 ImGui::InputFloat("##camera_position_z", &camera_position_vec[rig_dict[curr_rig_name]][current_cam_position_].z);
5212 ImGui::SameLine();
5213 ImGui::Text("Rig Position");
5214 // ####### CAMERA LOOKAT ####### //
5215 vec3 prev_rig_lookat = vec3(camera_lookat_vec[rig_dict[curr_rig_name]][current_cam_position_]);
5216 ImGui::SetNextItemWidth(60);
5217 ImGui::InputFloat("##camera_lookat_x", &camera_lookat_vec[rig_dict[curr_rig_name]][current_cam_position_].x);
5218 ImGui::SameLine();
5219 ImGui::SetNextItemWidth(60);
5220 ImGui::InputFloat("##camera_lookat_y", &camera_lookat_vec[rig_dict[curr_rig_name]][current_cam_position_].y);
5221 ImGui::SameLine();
5222 ImGui::SetNextItemWidth(60);
5223 ImGui::InputFloat("##camera_lookat_z", &camera_lookat_vec[rig_dict[curr_rig_name]][current_cam_position_].z);
5224 ImGui::SameLine();
5225 ImGui::Text("Rig Lookat");
5226
5227 if (prev_rig_position != camera_position_vec[rig_dict[curr_rig_name]][current_cam_position_] || prev_rig_lookat != camera_lookat_vec[rig_dict[curr_rig_name]][current_cam_position_]) {
5228 updateRigs();
5229 }
5230#endif
5231}
5232
5233void ProjectBuilder::lightTab() {
5234#if defined(ENABLE_HELIOS_VISUALIZER) && defined(ENABLE_RADIATION_MODEL)
5235 // LOAD XML LIBRARY FILE
5236 ImGui::SetNextItemWidth(60);
5237 if (ImGui::Button("Load XML Library File")) {
5238 std::string new_xml_library_file = file_dialog();
5239 if (!new_xml_library_file.empty() && std::filesystem::exists(new_xml_library_file)) {
5240 if (light_xml_library_files.find(new_xml_library_file) == light_xml_library_files.end()) {
5241 light_xml_library_files.insert(new_xml_library_file);
5242 std::vector<std::string> current_light_file = get_xml_node_values(new_xml_library_file, "label", "globaldata_vec2");
5243 possible_light_spectra.insert(possible_light_spectra.end(), current_light_file.begin(), current_light_file.end());
5244 }
5245 context->loadXML(new_xml_library_file.c_str());
5246 }
5247 }
5248 if (ImGui::BeginCombo("##light_combo", current_light.c_str())) {
5249 for (int n = 0; n < light_names.size(); n++) {
5250 bool is_light_selected = (current_light == light_names[n]);
5251 if (ImGui::Selectable(light_names[n].c_str(), is_light_selected))
5252 current_light = light_names[n];
5253 if (is_light_selected)
5254 ImGui::SetItemDefaultFocus();
5255 }
5256 ImGui::EndCombo();
5257 }
5258 ImGui::SameLine();
5259 if (ImGui::Button("Add Light")) {
5260 std::string default_light_name = "light";
5261 std::string new_light_name = "light_0";
5262 int count = 0;
5263 while (light_dict.find(new_light_name) != light_dict.end()) {
5264 count++;
5265 new_light_name = default_light_name + "_" + std::to_string(count);
5266 }
5267 light_dict.insert({new_light_name, scast<int>(light_names.size())});
5268 light_spectra.push_back(light_spectra[light_dict[current_light]]);
5269 light_types.push_back(light_types[light_dict[current_light]]);
5270 light_direction_vec.push_back(light_direction_vec[light_dict[current_light]]);
5271 light_direction_sph_vec.push_back(light_direction_sph_vec[light_dict[current_light]]);
5272 light_rotation_vec.push_back(light_rotation_vec[light_dict[current_light]]);
5273 light_size_vec.push_back(light_size_vec[light_dict[current_light]]);
5274 light_radius_vec.push_back(light_radius_vec[light_dict[current_light]]);
5275 light_names.push_back(new_light_name);
5276 light_flux_vec.push_back(light_flux_vec[light_dict[current_light]]);
5277 std::string parent = "light";
5278 pugi::xml_node light_block = helios.child(parent.c_str());
5279 pugi::xml_node new_light_node = helios.append_copy(light_block);
5280 std::string name = "label";
5281 pugi::xml_attribute node_label = new_light_node.attribute(name.c_str());
5282 node_label.set_value(new_light_name.c_str());
5283 current_light = new_light_name;
5284 }
5285 ImGui::SetNextItemWidth(100);
5286 std::string prev_light_name = light_names[light_dict[current_light]];
5287 ImGui::InputText("##light_name", &light_names[light_dict[current_light]]);
5288 if (light_names[light_dict[current_light]] != prev_light_name) {
5289 int temp = light_dict[current_light];
5290 current_light = light_names[light_dict[current_light]];
5291 std::map<std::string, int>::iterator current_light_iter = light_dict.find(prev_light_name);
5292 if (current_light_iter != light_dict.end()) {
5293 light_dict.erase(current_light_iter);
5294 }
5295 light_dict[current_light] = temp;
5296 }
5297 ImGui::SameLine();
5298 ImGui::Text("Light Label");
5299 // ####### LIGHT SPECTRA ####### //
5300 std::string prev_light_spectra = light_spectra[light_dict[current_light]];
5301 if (ImGui::BeginCombo("##light_spectra_combo", light_spectra[light_dict[current_light]].c_str())) {
5302 for (int n = 0; n < possible_light_spectra.size(); n++) {
5303 bool is_light_spectra_selected = (light_spectra[light_dict[current_light]] == possible_light_spectra[n]);
5304 if (ImGui::Selectable(possible_light_spectra[n].c_str(), is_light_spectra_selected))
5305 light_spectra[light_dict[current_light]] = possible_light_spectra[n];
5306 if (is_light_spectra_selected)
5307 ImGui::SetItemDefaultFocus();
5308 }
5309 ImGui::EndCombo();
5310 }
5311 ImGui::SameLine();
5312 ImGui::Text("Light Spectrum");
5313 // ####### LIGHT TYPE ############ //
5314 if (ImGui::BeginCombo("##light_type_combo", light_types[light_dict[current_light]].c_str())) {
5315 for (int n = 0; n < all_light_types.size(); n++) {
5316 bool is_type_selected = (light_types[light_dict[current_light]] == all_light_types[n]);
5317 if (ImGui::Selectable(all_light_types[n].c_str(), is_type_selected)) {
5318 light_types[light_dict[current_light]] = all_light_types[n];
5319 }
5320 if (is_type_selected)
5321 ImGui::SetItemDefaultFocus();
5322 }
5323 ImGui::EndCombo();
5324 }
5325 ImGui::SameLine();
5326 ImGui::Text("Light Type");
5327 // collimated -> direction
5328 // disk -> position, radius, rotation
5329 // sphere -> position, radius
5330 // sunsphere -> direction
5331 // rectangle -> position, size, rotation
5332 // ####### LIGHT DIRECTION ####### //
5333 if (light_types[light_dict[(std::string) current_light]] == "collimated" || light_types[light_dict[(std::string) current_light]] == "sunsphere") {
5334 ImGui::SetNextItemWidth(90);
5335 ImGui::InputFloat("##light_direction_x", &light_direction_vec[light_dict[current_light]].x);
5336 randomizePopup("light_direction_x_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_direction_vec[light_dict[current_light]].x));
5337 randomizerParams("light_direction_x_" + std::to_string(light_dict[current_light]));
5338 ImGui::OpenPopupOnItemClick(("light_direction_x_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5339 ImGui::SameLine();
5340 ImGui::SetNextItemWidth(90);
5341 ImGui::InputFloat("##light_direction_y", &light_direction_vec[light_dict[current_light]].y);
5342 randomizePopup("light_direction_y_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_direction_vec[light_dict[current_light]].y));
5343 randomizerParams("light_direction_y_" + std::to_string(light_dict[current_light]));
5344 ImGui::OpenPopupOnItemClick(("light_direction_y_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5345 ImGui::SameLine();
5346 ImGui::SetNextItemWidth(90);
5347 ImGui::InputFloat("##light_direction_z", &light_direction_vec[light_dict[current_light]].z);
5348 randomizePopup("light_direction_z_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_direction_vec[light_dict[current_light]].z));
5349 randomizerParams("light_direction_z_" + std::to_string(light_dict[current_light]));
5350 ImGui::OpenPopupOnItemClick(("light_direction_z_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5351 ImGui::SameLine();
5352 ImGui::Text("Light Direction");
5353 }
5354 // ####### LIGHT SOURCE FLUX ####### //
5355 ImGui::SetNextItemWidth(90);
5356 ImGui::InputFloat("##source_flux", &light_flux_vec[light_dict[current_light]]);
5357 randomizePopup("source_flux_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_flux_vec[light_dict[current_light]]));
5358 randomizerParams("source_flux_" + std::to_string(light_dict[current_light]));
5359 ImGui::OpenPopupOnItemClick(("source_flux_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5360 ImGui::SameLine();
5361 ImGui::Text("Source Flux");
5362 // radiation->setSourceFlux(light_UUID, band, flux_value);
5363 // ####### LIGHT ROTATION ####### //
5364 if (light_types[light_dict[current_light]] == "disk" || light_types[light_dict[current_light]] == "rectangle") {
5365 ImGui::SetNextItemWidth(90);
5366 ImGui::InputFloat("##light_rotation_x", &light_rotation_vec[light_dict[current_light]].x);
5367 randomizePopup("light_rotation_x_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_rotation_vec[light_dict[current_light]].x));
5368 randomizerParams("light_rotation_x_" + std::to_string(light_dict[current_light]));
5369 ImGui::OpenPopupOnItemClick(("light_rotation_x_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5370 ImGui::SameLine();
5371 ImGui::SetNextItemWidth(90);
5372 ImGui::InputFloat("##light_rotation_y", &light_rotation_vec[light_dict[current_light]].y);
5373 randomizePopup("light_rotation_y_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_rotation_vec[light_dict[current_light]].y));
5374 randomizerParams("light_rotation_y_" + std::to_string(light_dict[current_light]));
5375 ImGui::OpenPopupOnItemClick(("light_rotation_y_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5376 ImGui::SameLine();
5377 ImGui::SetNextItemWidth(90);
5378 ImGui::InputFloat("##light_rotation_z", &light_rotation_vec[light_dict[current_light]].z);
5379 randomizePopup("light_rotation_z_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_rotation_vec[light_dict[current_light]].z));
5380 randomizerParams("light_rotation_z_" + std::to_string(light_dict[current_light]));
5381 ImGui::OpenPopupOnItemClick(("light_rotation_z_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5382 ImGui::SameLine();
5383 ImGui::Text("Light Rotation");
5384 }
5385 // ####### LIGHT SIZE ####### //
5386 if (light_types[light_dict[current_light]] == "rectangle") {
5387 ImGui::SetNextItemWidth(90);
5388 ImGui::InputFloat("##light_size_x", &light_size_vec[light_dict[current_light]].x);
5389 randomizePopup("light_size_x_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_size_vec[light_dict[current_light]].x));
5390 randomizerParams("light_size_x_" + std::to_string(light_dict[current_light]));
5391 ImGui::OpenPopupOnItemClick(("light_size_x_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5392 ImGui::SameLine();
5393 ImGui::SetNextItemWidth(90);
5394 ImGui::InputFloat("##light_size_y", &light_size_vec[light_dict[current_light]].y);
5395 randomizePopup("light_size_y_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_size_vec[light_dict[current_light]].y));
5396 randomizerParams("light_size_y_" + std::to_string(light_dict[current_light]));
5397 ImGui::OpenPopupOnItemClick(("light_size_y_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5398 ImGui::SameLine();
5399 ImGui::Text("Light Size");
5400 }
5401 // ####### LIGHT RADIUS ####### //
5402 if (light_types[light_dict[current_light]] == "disk" || light_types[light_dict[current_light]] == "sphere") {
5403 ImGui::SetNextItemWidth(90);
5404 ImGui::InputFloat("##light_radius", &light_radius_vec[light_dict[current_light]]);
5405 randomizePopup("light_radius_" + std::to_string(light_dict[current_light]), createTaggedPtr(&light_radius_vec[light_dict[current_light]]));
5406 randomizerParams("light_radius_" + std::to_string(light_dict[current_light]));
5407 ImGui::OpenPopupOnItemClick(("light_radius_" + std::to_string(light_dict[current_light])).c_str(), ImGuiPopupFlags_MouseButtonRight);
5408 ImGui::SameLine();
5409 ImGui::Text("Light Radius");
5410 }
5411 // LIGHT END
5412#endif
5413}
5414
5415
5416void ProjectBuilder::canopyTab(std::string curr_canopy_name, int id) {
5417#if defined(ENABLE_PLANT_ARCHITECTURE) && defined(ENABLE_HELIOS_VISUALIZER)
5418 if (ImGui::Button("Update Canopy")) {
5419 updateCanopy(curr_canopy_name);
5420 is_dirty = true;
5421 canopy_dict[current_canopy].is_dirty = false;
5422 }
5423 ImGui::SameLine();
5424 if (ImGui::Button("Delete Canopy")) {
5425 deleteCanopy(curr_canopy_name);
5426 is_dirty = true;
5427 canopy_dict[current_canopy].is_dirty = false;
5428 }
5429 if (canopy_dict[curr_canopy_name].is_dirty) {
5430 ImGui::SameLine();
5431 ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); // Red text
5432 ImGui::Text("update required");
5433 ImGui::PopStyleColor();
5434 }
5435 ImGui::SetNextItemWidth(100);
5436 std::string prev_canopy_name = canopy_dict[curr_canopy_name].label;
5437 ImGui::InputText("##canopy_name", &canopy_dict[curr_canopy_name].label);
5438 if (canopy_dict[curr_canopy_name].label != prev_canopy_name && canopy_labels_set.find(canopy_dict[curr_canopy_name].label) == canopy_labels_set.end() && !canopy_dict[curr_canopy_name].label.empty()) {
5439 canopy temp = canopy_dict[curr_canopy_name];
5440 curr_canopy_name = canopy_dict[curr_canopy_name].label;
5441 std::map<std::string, canopy>::iterator current_canopy_iter = canopy_dict.find(prev_canopy_name);
5442 if (current_canopy_iter != canopy_dict.end()) {
5443 canopy_dict.erase(current_canopy_iter);
5444 }
5445 canopy_dict[curr_canopy_name] = temp;
5446
5447 canopy_labels_set.erase(prev_canopy_name);
5448 canopy_labels_set.insert(canopy_dict[curr_canopy_name].label);
5449 } else {
5450 canopy_dict[curr_canopy_name].label = prev_canopy_name;
5451 }
5452 vec3 prev_canopy_origin_ = vec3(canopy_dict[curr_canopy_name].origin);
5453 ImGui::SetNextItemWidth(60);
5454 ImGui::InputFloat("##canopy_origin_x", &canopy_dict[curr_canopy_name].origin.x);
5455 ImGui::SameLine();
5456 ImGui::SetNextItemWidth(60);
5457 ImGui::InputFloat("##canopy_origin_y", &canopy_dict[curr_canopy_name].origin.y);
5458 ImGui::SameLine();
5459 ImGui::SetNextItemWidth(60);
5460 ImGui::InputFloat("##canopy_origin_z", &canopy_dict[curr_canopy_name].origin.z);
5461 ImGui::SameLine();
5462 ImGui::Text("Canopy Origin");
5463 // ####### PLANT COUNT ####### //
5464 int2 prev_plant_count_ = int2(canopy_dict[curr_canopy_name].plant_count);
5465 ImGui::SetNextItemWidth(100);
5466 ImGui::InputInt("##plant_count_x", &canopy_dict[curr_canopy_name].plant_count.x);
5467 ImGui::SameLine();
5468 ImGui::SetNextItemWidth(100);
5469 ImGui::InputInt("##plant_count_y", &canopy_dict[curr_canopy_name].plant_count.y);
5470 ImGui::SameLine();
5471 ImGui::Text("Plant Count");
5472 // ####### PLANT SPACING ####### //
5473 vec2 prev_plant_spacing_ = vec2(canopy_dict[curr_canopy_name].plant_spacing);
5474 ImGui::SetNextItemWidth(50);
5475 ImGui::InputFloat("##plant_spacing_x", &canopy_dict[curr_canopy_name].plant_spacing.x);
5476 ImGui::SameLine();
5477 ImGui::SetNextItemWidth(50);
5478 ImGui::InputFloat("##plant_spacing_y", &canopy_dict[curr_canopy_name].plant_spacing.y);
5479 ImGui::SameLine();
5480 ImGui::Text("Plant Spacing");
5481 // ####### PLANT LIBRARY NAME ####### //
5482 std::string prev_plant_library_ = canopy_dict[curr_canopy_name].library_name;
5483 ImGui::SetNextItemWidth(250);
5484 dropDown("Plant Library###dropdown", canopy_dict[curr_canopy_name].library_name_verbose, plant_types_verbose);
5485 canopy_dict[curr_canopy_name].library_name = plant_type_lookup[canopy_dict[curr_canopy_name].library_name_verbose];
5486 // ####### PLANT AGE ####### //
5487 float prev_plant_age_ = canopy_dict[curr_canopy_name].age;
5488 ImGui::SetNextItemWidth(80);
5489 ImGui::InputFloat("Plant Age", &canopy_dict[curr_canopy_name].age);
5490 // ####### GROUND CLIPPING HEIGHT ####### //
5491 float prev_ground_clipping_height_ = canopy_dict[curr_canopy_name].ground_clipping_height;
5492 ImGui::SetNextItemWidth(80);
5493 ImGui::InputFloat("Ground Clipping Height", &canopy_dict[curr_canopy_name].ground_clipping_height);
5494 if (prev_canopy_origin_ != canopy_dict[curr_canopy_name].origin || prev_plant_count_ != canopy_dict[curr_canopy_name].plant_count || prev_plant_spacing_ != canopy_dict[curr_canopy_name].plant_spacing ||
5495 prev_plant_library_ != canopy_dict[curr_canopy_name].library_name || prev_plant_age_ != canopy_dict[curr_canopy_name].age || prev_ground_clipping_height_ != canopy_dict[curr_canopy_name].ground_clipping_height) {
5496 canopy_dict[curr_canopy_name].is_dirty = true;
5497 }
5498#endif // PLANT_ARCHITECTURE
5499}
5500
5501void ProjectBuilder::saveCanopy(std::string file_name, std::vector<uint> canopy_ID_vec, vec3 position, std::string file_extension) const {
5502#ifdef ENABLE_PLANT_ARCHITECTURE
5503 std::vector<std::string> primitive_data_vec = {"object_label"};
5504 std::vector<uint> canopy_primID_vec;
5505 std::vector<uint> canopy_objID_vec;
5506 // plantarchitecture->getAllPlantObjectIDs(plantID)
5507 for (int i = 0; i < canopy_ID_vec.size(); i++) {
5508 std::vector<uint> canopy_prim_UUIDs = plantarchitecture->getAllPlantUUIDs(canopy_ID_vec[i]);
5509 std::vector<uint> canopy_obj_UUIDs = plantarchitecture->getAllPlantObjectIDs(canopy_ID_vec[i]);
5510 canopy_primID_vec.insert(canopy_primID_vec.end(), canopy_prim_UUIDs.begin(), canopy_prim_UUIDs.end());
5511 canopy_objID_vec.insert(canopy_objID_vec.end(), canopy_obj_UUIDs.begin(), canopy_obj_UUIDs.end());
5512 }
5513 for (uint objID: canopy_objID_vec) {
5514 context->translateObject(objID, -position);
5515 }
5516 if (file_extension == "obj") {
5517 context->writeOBJ(file_name, canopy_primID_vec, primitive_data_vec, true);
5518 } else if (file_extension == "ply") {
5519 // context->writePLY(file_name, obj_UUID_vec, primitive_data_vec);
5520 }
5521 for (uint objID: canopy_objID_vec) {
5522 context->translateObject(objID, position);
5523 }
5524#endif
5525}
5526
5527void ProjectBuilder::saveCanopy(std::string file_name_base, std::vector<uint> canopy_ID_vec, std::vector<helios::vec3> positions, std::string file_extension) const {
5528#ifdef ENABLE_PLANT_ARCHITECTURE
5529 std::vector<std::string> primitive_data_vec = {"object_label"};
5530 std::vector<std::vector<uint>> canopy_primID_vec;
5531 std::vector<std::vector<uint>> canopy_objID_vec;
5532 // plantarchitecture->getAllPlantObjectIDs(plantID)
5533 for (int i = 0; i < canopy_ID_vec.size(); i++) {
5534 std::vector<uint> canopy_prim_UUIDs = plantarchitecture->getAllPlantUUIDs(canopy_ID_vec[i]);
5535 std::vector<uint> canopy_obj_UUIDs = plantarchitecture->getAllPlantObjectIDs(canopy_ID_vec[i]);
5536 canopy_primID_vec.push_back(canopy_prim_UUIDs);
5537 canopy_objID_vec.push_back(canopy_obj_UUIDs);
5538 }
5539 for (int i = 0; i < canopy_objID_vec.size(); i++) {
5540 for (uint objID: canopy_objID_vec[i]) {
5541 context->translateObject(objID, -positions[i]);
5542 }
5543 }
5544 std::filesystem::path file_path(file_name_base);
5545 std::string ext = file_path.extension().string();
5546 file_path.replace_extension("");
5547 std::string file_name = file_path.string();
5548 if (file_extension == "obj") {
5549 for (int i = 0; i < canopy_primID_vec.size(); i++) {
5550 context->writeOBJ(file_name + "_" + std::to_string(i) + ext, canopy_primID_vec[i], primitive_data_vec, true);
5551 }
5552 } else if (file_extension == "ply") {
5553 // context->writePLY(file_name, obj_UUID_vec, primitive_data_vec);
5554 }
5555 for (int i = 0; i < canopy_objID_vec.size(); i++) {
5556 for (uint objID: canopy_objID_vec[i]) {
5557 context->translateObject(objID, positions[i]);
5558 }
5559 }
5560#endif
5561}
5562
5563void ProjectBuilder::addBand(std::string label, float wavelength_min, float wavelength_max, bool enable_emission) {
5564#ifdef ENABLE_RADIATION_MODEL
5565 if (label.empty()) {
5566 std::cout << "Failed to add band. Please specify a band label." << std::endl;
5567 return;
5568 }
5569 if (bandlabels_set.find(label) != bandlabels_set.end()) {
5570 std::cout << "Failed to add band. Band with the specified name already exists." << std::endl;
5571 return;
5572 }
5573 if (wavelength_min > wavelength_max) {
5574 std::cout << "Failed to add band. Invalid wavelength minimum and maximum." << std::endl;
5575 return;
5576 }
5577 bandlabels.push_back(label);
5578 bandlabels_set.insert(label);
5579 primitive_values[label] = {{"All", {reflectivity, transmissivity, emissivity}},
5580 {"ground", {ground_reflectivity, ground_transmissivity, ground_emissivity}},
5581 {"leaf", {leaf_reflectivity, leaf_transmissivity, leaf_emissivity}},
5582 {"petiolule", {petiolule_reflectivity, petiolule_transmissivity, petiolule_emissivity}},
5583 {"petiole", {petiole_reflectivity, petiole_transmissivity, petiole_emissivity}},
5584 {"internode", {internode_reflectivity, internode_transmissivity, internode_emissivity}},
5585 {"peduncle", {peduncle_reflectivity, peduncle_transmissivity, peduncle_emissivity}},
5586 {"petal", {petal_reflectivity, petal_transmissivity, petal_emissivity}},
5587 {"pedicel", {pedicel_reflectivity, pedicel_transmissivity, pedicel_emissivity}},
5588 {"fruit", {fruit_reflectivity, fruit_transmissivity, fruit_emissivity}}};
5589 for (auto &primitive_values_pair: primitive_values_dict) {
5590 primitive_values_dict[primitive_values_pair.first][label] = {{"All", {reflectivity, transmissivity, emissivity}},
5591 {"ground", {ground_reflectivity, ground_transmissivity, ground_emissivity}},
5592 {"leaf", {leaf_reflectivity, leaf_transmissivity, leaf_emissivity}},
5593 {"petiolule", {petiolule_reflectivity, petiolule_transmissivity, petiolule_emissivity}},
5594 {"petiole", {petiole_reflectivity, petiole_transmissivity, petiole_emissivity}},
5595 {"internode", {internode_reflectivity, internode_transmissivity, internode_emissivity}},
5596 {"peduncle", {peduncle_reflectivity, peduncle_transmissivity, peduncle_emissivity}},
5597 {"petal", {petal_reflectivity, petal_transmissivity, petal_emissivity}},
5598 {"pedicel", {pedicel_reflectivity, pedicel_transmissivity, pedicel_emissivity}},
5599 {"fruit", {fruit_reflectivity, fruit_transmissivity, fruit_emissivity}}};
5600 }
5601 radiation->addRadiationBand(label, wavelength_min, wavelength_max);
5602 // radiation->addRadiationBand(label);
5603 if (!enable_emission) {
5604 radiation->disableEmission(label);
5605 } else {
5606 bandlabels_set_emissivity.insert(label);
5607 }
5608 radiation->setDirectRayCount(label, direct_ray_count);
5609 direct_ray_count_dict.insert({label, direct_ray_count});
5610 radiation->setDiffuseRayCount(label, diffuse_ray_count);
5611 diffuse_ray_count_dict.insert({label, diffuse_ray_count});
5612 radiation->setScatteringDepth(label, scattering_depth);
5613 scattering_depth_dict.insert({label, scattering_depth});
5614#endif
5615}
5616
5617void ProjectBuilder::addBand(std::string label, bool enable_emission) {
5618#ifdef ENABLE_RADIATION_MODEL
5619 if (label.empty()) {
5620 std::cout << "Failed to add band. Please specify a band label." << std::endl;
5621 return;
5622 }
5623 if (bandlabels_set.find(label) != bandlabels_set.end()) {
5624 std::cout << "Failed to add band. Band with the specified name already exists." << std::endl;
5625 return;
5626 }
5627 bandlabels.push_back(label);
5628 bandlabels_set.insert(label);
5629 primitive_values[label] = {{"All", {reflectivity, transmissivity, emissivity}},
5630 {"ground", {ground_reflectivity, ground_transmissivity, ground_emissivity}},
5631 {"leaf", {leaf_reflectivity, leaf_transmissivity, leaf_emissivity}},
5632 {"petiolule", {petiolule_reflectivity, petiolule_transmissivity, petiolule_emissivity}},
5633 {"petiole", {petiole_reflectivity, petiole_transmissivity, petiole_emissivity}},
5634 {"internode", {internode_reflectivity, internode_transmissivity, internode_emissivity}},
5635 {"peduncle", {peduncle_reflectivity, peduncle_transmissivity, peduncle_emissivity}},
5636 {"petal", {petal_reflectivity, petal_transmissivity, petal_emissivity}},
5637 {"pedicel", {pedicel_reflectivity, pedicel_transmissivity, pedicel_emissivity}},
5638 {"fruit", {fruit_reflectivity, fruit_transmissivity, fruit_emissivity}}};
5639 for (auto &primitive_values_pair: primitive_values_dict) {
5640 primitive_values_dict[primitive_values_pair.first][label] = {{"All", {reflectivity, transmissivity, emissivity}},
5641 {"ground", {ground_reflectivity, ground_transmissivity, ground_emissivity}},
5642 {"leaf", {leaf_reflectivity, leaf_transmissivity, leaf_emissivity}},
5643 {"petiolule", {petiolule_reflectivity, petiolule_transmissivity, petiolule_emissivity}},
5644 {"petiole", {petiole_reflectivity, petiole_transmissivity, petiole_emissivity}},
5645 {"internode", {internode_reflectivity, internode_transmissivity, internode_emissivity}},
5646 {"peduncle", {peduncle_reflectivity, peduncle_transmissivity, peduncle_emissivity}},
5647 {"petal", {petal_reflectivity, petal_transmissivity, petal_emissivity}},
5648 {"pedicel", {pedicel_reflectivity, pedicel_transmissivity, pedicel_emissivity}},
5649 {"fruit", {fruit_reflectivity, fruit_transmissivity, fruit_emissivity}}};
5650 }
5652 // radiation->addRadiationBand(label);
5653 if (!enable_emission) {
5654 radiation->disableEmission(label);
5655 } else {
5656 bandlabels_set_emissivity.insert(label);
5657 }
5658 radiation->setDirectRayCount(label, direct_ray_count);
5659 direct_ray_count_dict.insert({label, direct_ray_count});
5660 radiation->setDiffuseRayCount(label, diffuse_ray_count);
5661 diffuse_ray_count_dict.insert({label, diffuse_ray_count});
5662 radiation->setScatteringDepth(label, scattering_depth);
5663 scattering_depth_dict.insert({label, scattering_depth});
5664#endif
5665}
5666
5667
5668#ifdef ENABLE_HELIOS_VISUALIZER
5669void ProjectBuilder::randomizePopup(std::string popup_name, taggedPtr ptr) {
5670 std::string popup = "randomize_" + popup_name;
5671 if (ImGui::BeginPopup(popup.c_str())) {
5672 ImGui::Text("Random Distribution");
5673 ImGui::SetNextItemWidth(150);
5674 if (ImGui::BeginCombo("##combo_distribution", current_distribution.c_str())) {
5675 for (int n = 0; n < distribution_names.size(); n++) {
5676 bool is_dist_selected = (current_distribution == distribution_names[n]);
5677 if (ImGui::Selectable(distribution_names[n].c_str(), is_dist_selected))
5678 current_distribution = distribution_names[n];
5679 if (is_dist_selected)
5680 ImGui::SetItemDefaultFocus();
5681 }
5682 ImGui::EndCombo();
5683 }
5684 if (current_distribution == "Normal (Gaussian)") {
5685 ImGui::SetNextItemWidth(150);
5686 ImGui::InputFloat("Mean", &curr_distribution_params[0]);
5687 ImGui::SetNextItemWidth(150);
5688 ImGui::InputFloat("Variance", &curr_distribution_params[1]);
5689 }
5690 if (current_distribution == "Uniform") {
5691 ImGui::SetNextItemWidth(150);
5692 ImGui::InputFloat("Lower Bound", &curr_distribution_params[0]);
5693 ImGui::SetNextItemWidth(150);
5694 ImGui::InputFloat("Upper Bound", &curr_distribution_params[1]);
5695 }
5696 if (current_distribution == "Weibull") {
5697 ImGui::SetNextItemWidth(150);
5698 ImGui::InputFloat("Shape (k)", &curr_distribution_params[0]);
5699 ImGui::SetNextItemWidth(150);
5700 ImGui::InputFloat(u8"Scale (\u03bb)", &curr_distribution_params[1]);
5701 }
5702 if (current_distribution != "N/A") {
5703 ImGui::Checkbox("Randomize for Every Image", &randomize_repeatedly);
5704 }
5705 if (ImGui::Button("Apply")) {
5706 applyDistribution(popup_name, ptr);
5707 ImGui::CloseCurrentPopup();
5708 }
5709 ImGui::EndPopup();
5710 }
5711}
5712#else
5713void ProjectBuilder::randomizePopup(std::string popup_name, taggedPtr ptr) {
5714 // Visualizer plugin is required for GUI functionality
5715}
5716#endif // ENABLE_HELIOS_VISUALIZER
5717
5718
5719#ifdef ENABLE_HELIOS_VISUALIZER
5720void ProjectBuilder::noisePopup(std::string popup_name, std::vector<distribution> &dist_vec) {
5721 std::string popup = popup_name;
5722 if (ImGui::BeginPopup(popup.c_str())) {
5723 ImGui::Text("Add Random Noise Along Path");
5724 ImGui::SetNextItemWidth(100);
5725 if (ImGui::BeginCombo("##axis_combo", current_axis.c_str())) {
5726 for (auto axis: possible_axes) {
5727 bool is_axis_selected = (current_axis == axis);
5728 if (ImGui::Selectable(axis.c_str(), is_axis_selected))
5729 current_axis = axis;
5730 if (is_axis_selected)
5731 ImGui::SetItemDefaultFocus();
5732 }
5733 ImGui::EndCombo();
5734 }
5735 ImGui::SameLine();
5736 ImGui::Text("Axis");
5737 ImGui::SetNextItemWidth(150);
5738 if (ImGui::BeginCombo("##combo_distribution", current_distribution.c_str())) {
5739 for (int n = 0; n < distribution_names.size(); n++) {
5740 bool is_dist_selected = (current_distribution == distribution_names[n]);
5741 if (ImGui::Selectable(distribution_names[n].c_str(), is_dist_selected))
5742 current_distribution = distribution_names[n];
5743 if (is_dist_selected)
5744 ImGui::SetItemDefaultFocus();
5745 }
5746 ImGui::EndCombo();
5747 }
5748 ImGui::SameLine();
5749 ImGui::Text("Distribution");
5750 if (current_distribution == "Normal (Gaussian)") {
5751 ImGui::SetNextItemWidth(150);
5752 ImGui::InputFloat("Mean", &curr_distribution_params[0]);
5753 ImGui::SetNextItemWidth(150);
5754 ImGui::InputFloat("Variance", &curr_distribution_params[1]);
5755 }
5756 if (current_distribution == "Uniform") {
5757 ImGui::SetNextItemWidth(150);
5758 ImGui::InputFloat("Lower Bound", &curr_distribution_params[0]);
5759 ImGui::SetNextItemWidth(150);
5760 ImGui::InputFloat("Upper Bound", &curr_distribution_params[1]);
5761 }
5762 if (current_distribution == "Weibull") {
5763 ImGui::SetNextItemWidth(150);
5764 ImGui::InputFloat("Shape (k)", &curr_distribution_params[0]);
5765 ImGui::SetNextItemWidth(150);
5766 ImGui::InputFloat(u8"Scale (\u03bb)", &curr_distribution_params[1]);
5767 }
5768 int idx;
5769 if (current_axis == "X") {
5770 idx = 0;
5771 } else if (current_axis == "Y") {
5772 idx = 1;
5773 } else {
5774 idx = 2;
5775 }
5776 if (ImGui::Button("Apply")) {
5777 distUnion dist_union{};
5778 if (current_distribution == "Normal (Gaussian)") {
5779 dist_union.normal = new std::normal_distribution<float>;
5780 *dist_union.normal = std::normal_distribution<float>(curr_distribution_params[0], curr_distribution_params[1]);
5781 dist_vec[idx].dist = dist_union;
5782 dist_vec[idx].flag = 0;
5783 dist_vec[idx].repeat = 0;
5784 }
5785 if (current_distribution == "Uniform") {
5786 dist_union.uniform = new std::uniform_real_distribution<float>;
5787 *dist_union.uniform = std::uniform_real_distribution<float>(curr_distribution_params[0], curr_distribution_params[1]);
5788 dist_vec[idx].dist = dist_union;
5789 dist_vec[idx].flag = 1;
5790 dist_vec[idx].repeat = 0;
5791 }
5792 if (current_distribution == "Weibull") {
5793 dist_union.weibull = new std::weibull_distribution<float>;
5794 *dist_union.weibull = std::weibull_distribution<float>(curr_distribution_params[0], curr_distribution_params[1]);
5795 dist_vec[idx].dist = dist_union;
5796 dist_vec[idx].flag = 2;
5797 dist_vec[idx].repeat = 0;
5798 }
5799 if (current_distribution == "N/A") {
5800 dist_vec[idx].flag = -1;
5801 dist_vec[idx].repeat = 0;
5802 }
5803
5804 ImGui::CloseCurrentPopup();
5805 }
5806 ImGui::EndPopup();
5807 }
5808}
5809#else
5810void ProjectBuilder::noisePopup(std::string popup_name, std::vector<distribution> &dist_vec) {
5811 // Visualizer plugin is required for GUI functionality
5812}
5813#endif // ENABLE_HELIOS_VISUALIZER
5814
5815
5816void ProjectBuilder::applyDistribution(std::string var_name, taggedPtr ptr) {
5817 if (current_distribution == "N/A") {
5818 distribution_types[var_name] = "N/A";
5819 }
5820 if (current_distribution == "Normal (Gaussian)") {
5821 std::normal_distribution<float> curr_dist_normal(curr_distribution_params[0], curr_distribution_params[1]);
5822 distribution_dict[var_name] = distributions.size();
5823 distributions.push_back(createDistribution(curr_dist_normal, randomize_repeatedly));
5824 distribution_types[var_name] = "Normal (Gaussian)";
5825 }
5826 if (current_distribution == "Uniform") {
5827 std::uniform_real_distribution<float> curr_dist_uniform(curr_distribution_params[0], curr_distribution_params[1]);
5828 distribution_dict[var_name] = distributions.size();
5829 distributions.push_back(createDistribution(curr_dist_uniform, randomize_repeatedly));
5830 distribution_types[var_name] = "Uniform";
5831 }
5832 if (current_distribution == "Weibull") {
5833 std::weibull_distribution<float> curr_dist_weibull(curr_distribution_params[0], curr_distribution_params[1]);
5834 distribution_dict[var_name] = distributions.size();
5835 distributions.push_back(createDistribution(curr_dist_weibull, randomize_repeatedly));
5836 distribution_types[var_name] = "Weibull";
5837 }
5838 distribution_params[var_name] = curr_distribution_params;
5839 randomized_variable_lookup[var_name] = ptr;
5840 sample(var_name);
5841}
5842
5843
5844void ProjectBuilder::applyDistribution(std::string var_name, distribution dist, taggedPtr ptr) {
5845 if (dist.flag == -1) {
5846 distribution_dict[var_name] = distributions.size();
5847 distributions.push_back(dist);
5848 distribution_types[var_name] = "N/A";
5849 distribution_params[var_name] = std::vector<float>{0.0, 0.0};
5850 }
5851 if (dist.flag == 0) {
5852 distribution_dict[var_name] = distributions.size();
5853 distributions.push_back(dist);
5854 distribution_types[var_name] = "Normal (Gaussian)";
5855 distribution_params[var_name] = std::vector<float>{dist.dist.normal->mean(), dist.dist.normal->stddev()};
5856 }
5857 if (current_distribution == "Uniform") {
5858 distribution_dict[var_name] = distributions.size();
5859 distributions.push_back(dist);
5860 distribution_types[var_name] = "Uniform";
5861 distribution_params[var_name] = std::vector<float>{dist.dist.uniform->a(), dist.dist.uniform->b()};
5862 }
5863 if (current_distribution == "Weibull") {
5864 distribution_dict[var_name] = distributions.size();
5865 distributions.push_back(dist);
5866 distribution_types[var_name] = "Weibull";
5867 distribution_params[var_name] = std::vector<float>{dist.dist.weibull->a(), dist.dist.weibull->b()};
5868 }
5869 randomized_variable_lookup[var_name] = ptr;
5870 sample(var_name);
5871}
5872
5873
5874void ProjectBuilder::randomize(bool randomize_all) {
5875 for (std::pair<std::string, int> dist_pair: distribution_dict) {
5876 std::string var_name = dist_pair.first;
5877 distribution dist = distributions[dist_pair.second];
5878 if (randomize_all || dist.repeat) {
5879 sample(var_name);
5880 }
5881 }
5882}
5883
5884
5886 digitPtr p;
5887 p.f = ptr;
5888 taggedPtr t{p, false};
5889 return t;
5890}
5891
5892
5894 digitPtr p;
5895 p.i = ptr;
5896 taggedPtr t{p, true};
5897 return t;
5898}
5899
5900
5901taggedPtr createTaggedPtr(float *ptr, bool *dirty) {
5902 digitPtr p;
5903 p.f = ptr;
5904 taggedPtr t{p, false, dirty};
5905 return t;
5906}
5907
5908
5909taggedPtr createTaggedPtr(int *ptr, bool *dirty) {
5910 digitPtr p;
5911 p.i = ptr;
5912 taggedPtr t{p, true, dirty};
5913 return t;
5914}
5915
5916
5917distribution createDistribution(const std::normal_distribution<float> &dist, bool randomize_repeat) {
5918 distUnion u;
5919 u.normal = new std::normal_distribution<float>;
5920 *u.normal = dist;
5921 distribution d{u, 0, randomize_repeat};
5922 return d;
5923}
5924
5925distribution createDistribution(const std::uniform_real_distribution<float> &dist, bool randomize_repeat) {
5926 distUnion u;
5927 u.uniform = new std::uniform_real_distribution<float>;
5928 *u.uniform = dist;
5929 distribution d{u, 1, randomize_repeat};
5930 return d;
5931}
5932
5933distribution createDistribution(const std::weibull_distribution<float> &dist, bool randomize_repeat) {
5934 distUnion u;
5935 u.weibull = new std::weibull_distribution<float>;
5936 *u.weibull = dist;
5937 distribution d{u, 2, randomize_repeat};
5938 return d;
5939}
5940
5941#ifdef ENABLE_HELIOS_VISUALIZER
5942void ProjectBuilder::randomizerParams(std::string var_name) {
5943 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
5944 if (distribution_params.find(var_name) != distribution_params.end()) {
5945 curr_distribution_params = distribution_params[var_name];
5946 } else {
5947 curr_distribution_params = std::vector<float>{0, 0};
5948 }
5949 if (distribution_types.find(var_name) != distribution_types.end()) {
5950 current_distribution = distribution_types[var_name];
5951 } else {
5952 current_distribution = "N/A";
5953 }
5954 if (current_distribution != "N/A") {
5955 randomize_repeatedly = distributions[distribution_dict[var_name]].repeat;
5956 }
5957 }
5958}
5959#else
5960void ProjectBuilder::randomizerParams(std::string var_name) {
5961 // Visualizer plugin is required for GUI functionality
5962}
5963#endif // ENABLE_HELIOS_VISUALIZER
5964
5965void ProjectBuilder::sample(std::string var_name) {
5966 if (distribution_types.find(var_name) == distribution_types.end() || distribution_types[var_name] == "N/A") {
5967 return;
5968 }
5969 distribution d = distributions[distribution_dict[var_name]];
5970 taggedPtr t = randomized_variable_lookup[var_name];
5971 float sampled_value;
5972 if (d.flag == 0) {
5973 std::normal_distribution<float> normal = *d.dist.normal;
5974 sampled_value = normal(generator);
5975 if (t.isInt) {
5976 *t.ptr.i = (int) sampled_value;
5977 } else {
5978 *t.ptr.f = sampled_value;
5979 }
5980 } else if (d.flag == 1) {
5981 std::uniform_real_distribution<float> uniform = *d.dist.uniform;
5982 sampled_value = uniform(generator);
5983 if (t.isInt) {
5984 *t.ptr.i = (int) sampled_value;
5985 } else {
5986 *t.ptr.f = sampled_value;
5987 }
5988 } else if (d.flag == 2) {
5989 std::weibull_distribution<float> weibull = *d.dist.weibull;
5990 sampled_value = weibull(generator);
5991 if (t.isInt) {
5992 *t.ptr.i = (int) sampled_value;
5993 } else {
5994 *t.ptr.f = sampled_value;
5995 }
5996 }
5997 // if (t.object.idx != -1){
5998 // if (t.object.isCanopy){
5999 // dirty_canopies.insert(t.object.idx);
6000 // } else{
6001 // dirty_objects.insert(t.object.idx);
6002 // }
6003 // }
6004}
6005
6006
6008 for (int canopy_idx: dirty_canopies) {
6009 // updateCanopy(canopy_idx);
6010 }
6011 for (int object_idx: dirty_objects) {
6012 updateObject(obj_names[object_idx]);
6013 }
6014 dirty_canopies.clear();
6015 dirty_objects.clear();
6016}
6017
6018
6020 for (std::pair<std::string, std::string> var_pair: distribution_types) {
6021 sample(var_pair.first);
6022 }
6023}
6024
6025#ifdef ENABLE_HELIOS_VISUALIZER
6026void ProjectBuilder::outputConsole() {
6027 // Temporarily restore std::cout so ImGui can print to the console without
6028 // altering the member pointer used by the destructor to restore the
6029 // original buffer at program exit.
6030 std::streambuf *prev_buf = std::cout.rdbuf();
6031 std::string buffer = captured_cout.str();
6032 std::size_t buffer_size = buffer.size();
6033 ImGui::BeginChild("##console", ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 5), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
6034 ImGui::TextUnformatted(buffer.c_str());
6035 if (buffer_size != last_console_size) {
6036 ImGui::SetScrollHereY(1.0f);
6037 }
6038 ImGui::EndChild();
6039 last_console_size = buffer_size;
6040 std::cout.rdbuf(prev_buf);
6041}
6042#else
6043void ProjectBuilder::outputConsole() {
6044 // Visualizer plugin is required for GUI functionality
6045}
6046#endif // ENABLE_HELIOS_VISUALIZER
6047
6048void ProjectBuilder::updateColor(std::string curr_obj, std::string obj_type, float *new_color) {
6049 RGBcolor *curr_color = nullptr;
6050 if (obj_type == "obj") {
6051 curr_color = &objects_dict[curr_obj].color;
6052 }
6053 if (obj_type == "rig" || obj_type == "arrow" || obj_type == "camera") {
6054 curr_color = &rig_colors[rig_dict[curr_obj]];
6055 }
6056 // if (curr_color->r == new_color[0] && curr_color->g == new_color[1] && curr_color->b == new_color[2]){
6057 // return;
6058 // }
6059 if (curr_color->r != new_color[0] || curr_color->g != new_color[1] || curr_color->b != new_color[2]) {
6060 is_dirty = true;
6061 }
6062 curr_color->r = new_color[0];
6063 curr_color->g = new_color[1];
6064 curr_color->b = new_color[2];
6065
6066 // Use material system for GUI color editing
6067 if (obj_type == "obj") {
6068 std::string obj_material = "projectbuilder_obj_" + curr_obj;
6069 if (!context->doesMaterialExist(obj_material)) {
6070 context->addMaterial(obj_material);
6071 context->assignMaterialToPrimitive(objects_dict[curr_obj].UUIDs, obj_material);
6072 }
6073 context->setMaterialColor(obj_material, make_RGBAcolor(*curr_color, 1.0f));
6074 }
6075 if (obj_type == "rig") {
6076 if (arrow_dict.find(curr_obj) != arrow_dict.end()) {
6077 std::string arrow_material = "projectbuilder_rig_arrow_" + curr_obj;
6078 if (!context->doesMaterialExist(arrow_material)) {
6079 context->addMaterial(arrow_material);
6080 for (std::vector<uint> &arrow: arrow_dict.at(curr_obj)) {
6081 context->assignMaterialToPrimitive(arrow, arrow_material);
6082 }
6083 }
6084 context->setMaterialColor(arrow_material, make_RGBAcolor(*curr_color, 1.0f));
6085 }
6086 if (camera_models_dict.find(curr_obj) != camera_models_dict.end()) {
6087 std::string camera_material = "projectbuilder_rig_camera_" + curr_obj;
6088 if (!context->doesMaterialExist(camera_material)) {
6089 context->addMaterial(camera_material);
6090 context->assignMaterialToPrimitive(camera_models_dict.at(curr_obj), camera_material);
6091 }
6092 context->setMaterialColor(camera_material, make_RGBAcolor(*curr_color, 1.0f));
6093 }
6094 }
6095 if (obj_type == "arrow") {
6096 if (arrow_dict.find(curr_obj) != arrow_dict.end()) {
6097 std::string arrow_material = "projectbuilder_arrow_" + curr_obj;
6098 if (!context->doesMaterialExist(arrow_material)) {
6099 context->addMaterial(arrow_material);
6100 for (std::vector<uint> &arrow: arrow_dict.at(curr_obj)) {
6101 context->assignMaterialToPrimitive(arrow, arrow_material);
6102 }
6103 }
6104 context->setMaterialColor(arrow_material, make_RGBAcolor(*curr_color, 1.0f));
6105 }
6106 }
6107 if (obj_type == "camera") {
6108 if (camera_models_dict.find(curr_obj) != camera_models_dict.end()) {
6109 std::string camera_material = "projectbuilder_camera_" + curr_obj;
6110 if (!context->doesMaterialExist(camera_material)) {
6111 context->addMaterial(camera_material);
6112 context->assignMaterialToPrimitive(camera_models_dict.at(curr_obj), camera_material);
6113 }
6114 context->setMaterialColor(camera_material, make_RGBAcolor(*curr_color, 1.0f));
6115 }
6116 }
6117}
6118
6119
6120void ProjectBuilder::updateObject(std::string curr_obj) {
6121 // Scale, rotate, and translate object
6122 if (objects_dict[curr_obj].use_texture_file && objects_dict[curr_obj].is_dirty) {
6123 context->deleteObject(objects_dict[curr_obj].objID);
6124 if (std::filesystem::path(objects_dict[curr_obj].file).extension() == ".obj") {
6125 objects_dict[curr_obj].UUIDs = context->loadOBJ(objects_dict[curr_obj].file.c_str());
6126 } else if (std::filesystem::path(objects_dict[curr_obj].file).extension() == ".ply") {
6127 objects_dict[curr_obj].UUIDs = context->loadPLY(objects_dict[curr_obj].file.c_str());
6128 }
6129 objects_dict[curr_obj].objID = context->addPolymeshObject(objects_dict[curr_obj].UUIDs);
6130
6131 context->scaleObject(objects_dict[curr_obj].objID, objects_dict[curr_obj].scale);
6132 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.x), "x");
6133 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.y), "y");
6134 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.z), "z");
6135 context->translateObject(objects_dict[curr_obj].objID, objects_dict[curr_obj].position);
6136
6137 objects_dict[curr_obj].prev_scale = objects_dict[curr_obj].scale;
6138 objects_dict[curr_obj].prev_orientation = objects_dict[curr_obj].orientation;
6139 objects_dict[curr_obj].prev_position = objects_dict[curr_obj].position;
6140 }
6141 if (objects_dict[curr_obj].scale != objects_dict[curr_obj].prev_scale) {
6142 vec3 obj_scale_;
6143 obj_scale_.x = objects_dict[curr_obj].scale.x / objects_dict[curr_obj].prev_scale.x;
6144 obj_scale_.y = objects_dict[curr_obj].scale.y / objects_dict[curr_obj].prev_scale.y;
6145 obj_scale_.z = objects_dict[curr_obj].scale.z / objects_dict[curr_obj].prev_scale.z;
6146 context->translateObject(objects_dict[curr_obj].objID, -objects_dict[curr_obj].prev_position); // translate back to origin
6147 context->rotateObject(objects_dict[curr_obj].objID, -deg2rad(objects_dict[curr_obj].prev_orientation.x), "x");
6148 context->rotateObject(objects_dict[curr_obj].objID, -deg2rad(objects_dict[curr_obj].prev_orientation.y), "y");
6149 context->rotateObject(objects_dict[curr_obj].objID, -deg2rad(objects_dict[curr_obj].prev_orientation.z), "z");
6150
6151 context->scaleObject(objects_dict[curr_obj].objID, obj_scale_);
6152 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].prev_orientation.x), "x");
6153 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].prev_orientation.y), "y");
6154 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].prev_orientation.z), "z");
6155 context->translateObject(objects_dict[curr_obj].objID, objects_dict[curr_obj].prev_position); // restore translation
6156 objects_dict[curr_obj].prev_scale = objects_dict[curr_obj].scale;
6157 }
6158 if (objects_dict[curr_obj].orientation != objects_dict[curr_obj].prev_orientation) {
6159 // context->rotatePrimitive(origin = prev_position, axis = (1,0,0));
6160 // rotate about x
6161 // context->rotatePrimitive(objects_dict[curr_obj].UUIDs, deg2rad(objects_dict[curr_obj].orientation.x - objects_dict[curr_obj].prev_orientation.x), objects_dict[curr_obj].prev_position, make_vec3(1, 0, 0));
6162 // context->rotatePrimitive(objects_dict[curr_obj].UUIDs, deg2rad(objects_dict[curr_obj].orientation.y - objects_dict[curr_obj].prev_orientation.y), objects_dict[curr_obj].prev_position, make_vec3(0, 1, 0));
6163 // context->rotatePrimitive(objects_dict[curr_obj].UUIDs, deg2rad(objects_dict[curr_obj].orientation.z - objects_dict[curr_obj].prev_orientation.z), objects_dict[curr_obj].prev_position, make_vec3(0, 0, 1));
6164 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.x - objects_dict[curr_obj].prev_orientation.x), objects_dict[curr_obj].prev_position, make_vec3(1, 0, 0));
6165 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.y - objects_dict[curr_obj].prev_orientation.y), objects_dict[curr_obj].prev_position, make_vec3(0, 1, 0));
6166 context->rotateObject(objects_dict[curr_obj].objID, deg2rad(objects_dict[curr_obj].orientation.z - objects_dict[curr_obj].prev_orientation.z), objects_dict[curr_obj].prev_position, make_vec3(0, 0, 1));
6167 objects_dict[curr_obj].prev_orientation = objects_dict[curr_obj].orientation;
6168 }
6169 if (objects_dict[curr_obj].position != objects_dict[curr_obj].prev_position) {
6170 // context->translatePrimitive(objects_dict[curr_obj].UUIDs, objects_dict[curr_obj].position - objects_dict[curr_obj].prev_position);
6171 context->translateObject(objects_dict[curr_obj].objID, objects_dict[curr_obj].position - objects_dict[curr_obj].prev_position);
6172 objects_dict[curr_obj].prev_position = objects_dict[curr_obj].position;
6173 }
6174 objects_dict[curr_obj].prev_color = objects_dict[curr_obj].color;
6175 objects_dict[curr_obj].is_dirty = false;
6176
6177 is_dirty = true;
6178}
6179
6180
6182 deleteArrows();
6183 arrow_dict.clear();
6184 updateArrows();
6185 deleteCameraModels();
6186 camera_models_dict.clear();
6187 updateCameraModels();
6188 // Update visualizer
6189 // refreshVisualization();
6190 is_dirty = true;
6191}
6192
6193
6194void ProjectBuilder::deleteRig(std::string curr_rig) {
6195 int delete_idx = rig_dict[curr_rig];
6196 rig_dict.erase(rig_dict.find(curr_rig));
6197 rig_labels_set.erase(curr_rig);
6198 updateRigs();
6199 if (!rig_labels_set.empty() && current_rig == curr_rig) {
6200 current_rig = *rig_labels_set.begin();
6201 } else {
6202 current_rig = "";
6203 }
6204}
6205
6206
6207void ProjectBuilder::addRig(std::string new_rig_label) {
6208 rig new_rig;
6209 new_rig.label = new_rig_label;
6210
6211 if (current_rig.empty()) {
6212 // If there is no currently selected rig, use default values.
6213 new_rig.position = default_rig.position;
6214 new_rig.lookat = default_rig.position;
6215 new_rig.camera_labels = default_rig.camera_labels;
6216 new_rig.position_noise = default_rig.position_noise;
6217 new_rig.lookat_noise = default_rig.lookat_noise;
6218 new_rig.camera_positions = default_rig.camera_positions;
6219 new_rig.camera_lookats = default_rig.camera_lookats;
6220 new_rig.color = default_rig.color;
6221 new_rig.num_images = default_rig.num_images;
6222 new_rig.keypoint_frames = default_rig.keypoint_frames;
6223 } else {
6224 // If there is a currently selected rig, copy current values.
6225 rig curr_rig = rig_dict_.at(current_rig);
6226
6227 new_rig.label = curr_rig.label;
6228 new_rig.position = curr_rig.position;
6229 new_rig.lookat = curr_rig.lookat;
6230 new_rig.camera_labels = curr_rig.camera_labels;
6231 new_rig.position_noise = curr_rig.position_noise;
6232 new_rig.lookat_noise = curr_rig.lookat_noise;
6233 new_rig.camera_positions = curr_rig.camera_positions;
6234 new_rig.camera_lookats = curr_rig.camera_lookats;
6235 new_rig.color = curr_rig.color;
6236 new_rig.num_images = curr_rig.num_images;
6237 new_rig.keypoint_frames = curr_rig.keypoint_frames;
6238 }
6239
6240 rig_dict_.insert({new_rig_label, new_rig});
6241
6242 rig_dict.insert({new_rig_label, scast<int>(rig_labels.size())});
6243 camera_positions.push_back(camera_position);
6244 camera_lookats.push_back(camera_lookat);
6245 camera_labels.push_back(camera_label);
6246 camera_position_vec.push_back(camera_position_vec[rig_dict[current_rig]]);
6247 camera_lookat_vec.push_back(camera_lookat_vec[rig_dict[current_rig]]);
6248 rig_labels.push_back(new_rig_label);
6249 rig_labels_set.insert(new_rig_label);
6250 rig_camera_labels.push_back(rig_camera_labels[rig_dict[current_rig]]);
6251 rig_light_labels.push_back(rig_light_labels[rig_dict[current_rig]]);
6252 keypoint_frames.push_back(keypoint_frames[rig_dict[current_rig]]);
6253 num_images_vec.push_back(num_images_vec[rig_dict[current_rig]]);
6254 rig_colors.push_back(rig_colors[rig_dict[current_rig]]);
6255 rig_position_noise.push_back(std::vector<distribution>{distribution{}, distribution{}, distribution{}});
6256 rig_lookat_noise.push_back(std::vector<distribution>{distribution{}, distribution{}, distribution{}});
6257
6258 // Add default values for write flags
6259 write_depth.push_back(false);
6260 write_norm_depth.push_back(false);
6261 write_segmentation_mask.push_back(false);
6262
6263 // current_rig = new_rig_label;
6264 std::string parent = "rig";
6265 pugi::xml_node rig_block = helios.child(parent.c_str());
6266 pugi::xml_node new_rig_node = helios.append_copy(rig_block);
6267 std::string name = "label";
6268 pugi::xml_attribute node_label = new_rig_node.attribute(name.c_str());
6269 node_label.set_value(new_rig_label.c_str());
6270 current_rig = new_rig_label;
6271}
6272
6273
6274#ifdef ENABLE_HELIOS_VISUALIZER
6275void ProjectBuilder::dropDown(std::string widget_name, std::string &selected, std::vector<std::string> choices) {
6276 if (ImGui::BeginCombo(widget_name.c_str(), selected.c_str())) {
6277 for (int n = 0; n < choices.size(); n++) {
6278 bool is_selected = (selected == choices[n]);
6279 if (ImGui::Selectable(choices[n].c_str(), is_selected))
6280 selected = choices[n];
6281 if (is_selected)
6282 ImGui::SetItemDefaultFocus();
6283 }
6284 ImGui::EndCombo();
6285 }
6286}
6287
6288
6289void ProjectBuilder::dropDown(std::string widget_name, std::string &selected, std::set<std::string> choices) {
6290 if (ImGui::BeginCombo(widget_name.c_str(), selected.c_str())) {
6291 for (std::string choice: choices) {
6292 bool is_selected = (selected == choice);
6293 if (ImGui::Selectable(choice.c_str(), is_selected))
6294 selected = choice;
6295 if (is_selected)
6296 ImGui::SetItemDefaultFocus();
6297 }
6298 ImGui::EndCombo();
6299 }
6300}
6301#else
6302void ProjectBuilder::dropDown(std::string widget_name, std::string &selected, std::vector<std::string> choices) {
6303 // Visualizer plugin is required for GUI functionality
6304}
6305
6306void ProjectBuilder::dropDown(std::string widget_name, std::string &selected, std::set<std::string> choices) {
6307 // Visualizer plugin is required for GUI functionality
6308}
6309#endif // ENABLE_HELIOS_VISUALIZER
6310
6311void ProjectBuilder::deleteCanopy(const std::string &canopy) {
6312#ifdef ENABLE_PLANT_ARCHITECTURE
6313 for (auto plant_instance: canopy_dict[canopy].IDs) {
6314 plantarchitecture->deletePlantInstance(plant_instance);
6315 }
6316 canopy_dict.erase(canopy);
6317 canopy_labels_set.erase(canopy);
6318 if (!canopy_labels_set.empty() && current_canopy == canopy) {
6319 current_canopy = *canopy_labels_set.begin();
6320 } else {
6321 current_canopy = "";
6322 }
6323
6324 is_dirty = true;
6325#endif
6326}
6327
6328
6329void ProjectBuilder::deleteObject(const std::string &obj) {
6330 context->deletePrimitive(objects_dict[obj].UUIDs);
6331 objects_dict.erase(obj);
6332 obj_names_set.erase(obj);
6333 if (!obj_names_set.empty()) {
6334 current_obj = *obj_names_set.begin();
6335 } else {
6336 current_obj = "";
6337 }
6338
6339 is_dirty = true;
6340}
6341
6342
6343void ProjectBuilder::updateCanopy(const std::string &canopy) {
6344#ifdef ENABLE_PLANT_ARCHITECTURE
6345 for (auto plant_instance: canopy_dict[canopy].IDs) {
6346 plantarchitecture->deletePlantInstance(plant_instance);
6347 }
6348 plantarchitecture->loadPlantModelFromLibrary(canopy_dict[canopy].library_name);
6349 plantarchitecture->enableGroundClipping(canopy_dict[canopy].ground_clipping_height);
6350
6351 std::vector<uint> new_canopy_IDs = plantarchitecture->buildPlantCanopyFromLibrary(canopy_dict[canopy].origin, canopy_dict[canopy].plant_spacing, canopy_dict[canopy].plant_count, canopy_dict[canopy].age);
6352 std::vector<vec3> curr_plant_locations = plantarchitecture->getPlantBasePosition(new_canopy_IDs);
6353 canopy_dict[canopy].individual_plant_locations = curr_plant_locations;
6354
6355 leaf_UUIDs = plantarchitecture->getAllLeafUUIDs();
6356 primitive_UUIDs["leaf"] = leaf_UUIDs;
6357 internode_UUIDs = plantarchitecture->getAllInternodeUUIDs();
6358 primitive_UUIDs["internode"] = internode_UUIDs;
6359 petiole_UUIDs = plantarchitecture->getAllPetioleUUIDs();
6360 primitive_UUIDs["petiole"] = petiole_UUIDs;
6361 peduncle_UUIDs = plantarchitecture->getAllPeduncleUUIDs();
6362 primitive_UUIDs["peduncle"] = peduncle_UUIDs;
6363 std::vector<uint> flower_UUIDs = plantarchitecture->getAllFlowerUUIDs();
6364 petal_UUIDs = context->filterPrimitivesByData(flower_UUIDs, "object_label", "petal");
6365 sepal_UUIDs = context->filterPrimitivesByData(flower_UUIDs, "object_label", "sepal");
6366 if (petal_UUIDs.empty() && sepal_UUIDs.empty()) {
6367 petal_UUIDs = flower_UUIDs;
6368 sepal_UUIDs.clear();
6369 }
6370 fruit_UUIDs = plantarchitecture->getAllFruitUUIDs();
6371 primitive_UUIDs["petal"] = petal_UUIDs;
6372 primitive_UUIDs["sepal"] = sepal_UUIDs;
6373 primitive_UUIDs["flower"] = flower_UUIDs;
6374
6375 canopy_dict[canopy].IDs = new_canopy_IDs;
6376 canopy_dict[canopy].is_dirty = false;
6377#endif
6378}
6379
6380
6381void ProjectBuilder::addCanopy() {
6382 std::string default_canopy_label = "canopy";
6383 std::string new_canopy_label = "canopy_0";
6384 int count = 0;
6385 while (canopy_dict.find(new_canopy_label) != canopy_dict.end()) {
6386 count++;
6387 new_canopy_label = default_canopy_label + "_" + std::to_string(count);
6388 }
6389 canopy new_canopy;
6390 new_canopy.idx = canopy_idx;
6391 canopy_labels_set.insert(new_canopy_label);
6392 canopy_idx++;
6393 new_canopy.age = plant_age;
6394 new_canopy.ground_clipping_height = ground_clipping_height;
6395 new_canopy.label = new_canopy_label;
6396 new_canopy.library_name = plant_library_name;
6397 new_canopy.library_name_verbose = plant_library_name_verbose;
6398 new_canopy.IDs = std::vector<unsigned int>{};
6399 new_canopy.individual_plant_locations = std::vector<vec3>{};
6400 new_canopy.plant_spacing = plant_spacing;
6401 new_canopy.plant_count = plant_count;
6402 new_canopy.origin = canopy_origin;
6403 new_canopy.data_group = "";
6404 canopy_dict[new_canopy.label] = new_canopy;
6405
6406 current_canopy = new_canopy_label;
6407}
6408
6409
6410#ifdef ENABLE_HELIOS_VISUALIZER
6411void ProjectBuilder::refreshVisualization() {
6412 const char *font_name = "LCD";
6413 visualizer->addTextboxByCenter("LOADING...", vec3(.5, .5, 0), make_SphericalCoord(0, 0), RGB::red, 40, font_name, Visualizer::COORDINATES_WINDOW_NORMALIZED);
6417 if (enable_coordinate_axes) {
6418 visualizer->addCoordinateAxes(helios::make_vec3(0, 0, 0.05), helios::make_vec3(1, 1, 1), "positive");
6419 }
6421 updatePrimitiveTypes();
6422}
6423#else
6424void ProjectBuilder::refreshVisualization() {
6425 // Visualizer plugin is required for GUI functionality
6426}
6427#endif // ENABLE_HELIOS_VISUALIZER
6428
6429
6430#ifdef ENABLE_HELIOS_VISUALIZER
6431void ProjectBuilder::recordPopup() {
6432 if (ImGui::BeginPopup("repeat_record")) {
6433 ImGui::SetNextItemWidth(100);
6434 ImGui::InputInt("Number of Recordings", &num_recordings);
6435 num_recordings = std::max(num_recordings, 1);
6436 ImGui::EndPopup();
6437 }
6438}
6439#else
6440void ProjectBuilder::recordPopup() {
6441 // Visualizer plugin is required for GUI functionality
6442}
6443#endif // ENABLE_HELIOS_VISUALIZER
6444
6445
6447 Location location;
6448 location.latitude_deg = latitude;
6449 location.longitude_deg = longitude;
6450 location.UTC_offset = static_cast<float>(UTC_offset);
6451 context->setLocation(location);
6452}
6453
6454
6456 context->deletePrimitive(ground_UUIDs);
6457 if (context->doesObjectExist(ground_objID))
6458 context->deleteObject(ground_objID);
6459 ground_UUIDs.clear();
6460 primitive_UUIDs["ground"].clear();
6461
6462 // uint ground_objID = context->addTileObject( domain_origin, domain_extent, nullptr, ground_resolution, ground_texture_file.c_str() );
6463 if (!ground_model_file.empty() && ground_flag == 2 && use_ground_texture) {
6464 ground_UUIDs = context->loadOBJ(ground_model_file.c_str());
6465 context->translatePrimitive(ground_UUIDs, domain_origin);
6466 ground_objID = context->addPolymeshObject(ground_UUIDs);
6467 } else if (!ground_texture_file.empty() && ground_flag == 1 && use_ground_texture) {
6468 if (num_tiles.x > 1 || num_tiles.y > 1 || ground_resolution.x > 1 || ground_resolution.y > 1) {
6469 buildTiledGround(domain_origin, domain_extent, num_tiles, ground_resolution, ground_texture_file.c_str(), 0.f);
6470
6471 return;
6472 } else {
6473 ground_objID = context->addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution, ground_texture_file.c_str());
6474 ground_UUIDs = context->getObjectPrimitiveUUIDs(ground_objID);
6475 }
6476 } else if (ground_flag == 1 && !use_ground_texture) {
6477 RGBcolor ground_color_;
6478 ground_color_.r = ground_color[0];
6479 ground_color_.g = ground_color[1];
6480 ground_color_.b = ground_color[2];
6481
6482 if (num_tiles.x > 1 || num_tiles.y > 1 || ground_resolution.x > 1 || ground_resolution.y > 1) {
6483 buildTiledGround(domain_origin, domain_extent, num_tiles, ground_resolution, ground_color_, 0.f);
6484
6485 // Use material system for ground color
6486 std::string ground_material = "projectbuilder_ground";
6487 if (!context->doesMaterialExist(ground_material)) {
6488 context->addMaterial(ground_material);
6489 }
6490 context->setMaterialColor(ground_material, make_RGBAcolor(ground_color_, 1.0f));
6491 context->assignMaterialToPrimitive(ground_UUIDs, ground_material);
6492
6493 return;
6494 } else {
6495 ground_objID = context->addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution, ground_color_);
6496 ground_UUIDs = context->getObjectPrimitiveUUIDs(ground_objID);
6497 }
6498 } else if (ground_flag == 2 && !use_ground_texture) {
6499 RGBcolor ground_color_;
6500 ground_color_.r = ground_color[0];
6501 ground_color_.g = ground_color[1];
6502 ground_color_.b = ground_color[2];
6503 ground_UUIDs = context->loadOBJ(ground_model_file.c_str());
6504 ground_objID = context->addPolymeshObject(ground_UUIDs);
6505
6506 // Use material system for ground object color
6507 std::string ground_material = "projectbuilder_ground";
6508 if (!context->doesMaterialExist(ground_material)) {
6509 context->addMaterial(ground_material);
6510 }
6511 context->setMaterialColor(ground_material, make_RGBAcolor(ground_color_, 1.0f));
6512 context->assignMaterialToObject(ground_objID, ground_material);
6513 }
6514 // else {
6515 // ground_objID = context->addTileObject(domain_origin, domain_extent, nullrotation, ground_resolution);
6516 // ground_UUIDs = context->getObjectPrimitiveUUIDs(ground_objID);
6517 // }
6518 ground_UUIDs.clear();
6519 ground_UUIDs = context->getObjectPrimitiveUUIDs(ground_objID);
6520 context->cleanDeletedUUIDs(ground_UUIDs);
6521 context->setGlobalData("ground_UUIDs", ground_UUIDs);
6522 context->setPrimitiveData(ground_UUIDs, "twosided_flag", uint(0));
6523 context->setPrimitiveData(ground_UUIDs, "object_label", "ground");
6524 primitive_UUIDs["ground"] = ground_UUIDs;
6525}
6526
6527
6529 context->deletePrimitive(ground_UUIDs);
6530 if (context->doesObjectExist(ground_objID))
6531 context->deleteObject(ground_objID);
6532 ground_UUIDs.clear();
6533 primitive_UUIDs["ground"].clear();
6534}
6535
6536#ifdef ENABLE_HELIOS_VISUALIZER
6537void ProjectBuilder::refreshVisualizationTypes() {
6538 // primitive
6539 visualization_types_primitive.clear();
6540 for (auto &data: context->listAllPrimitiveDataLabels()) {
6541 visualization_types_primitive.insert(data);
6542 primitive_data_types[data] = context->getPrimitiveDataType(data.c_str());
6543 }
6544
6545 // object
6546 visualization_types_object.clear();
6547 for (auto &data: context->listAllObjectDataLabels()) {
6548 visualization_types_object.insert(data);
6549 }
6550}
6551#else
6552void ProjectBuilder::refreshVisualizationTypes() {
6553 // Visualizer plugin is required for GUI functionality
6554}
6555#endif // ENABLE_HELIOS_VISUALIZER
6556
6557
6558std::string ProjectBuilder::shortenPath(std::string path_name) {
6559 std::string shorten_path = path_name;
6560 for (char &c: shorten_path) {
6561 if (c == '\\') {
6562 c = '/';
6563 }
6564 }
6565 size_t last_file = shorten_path.rfind('/');
6566 if (last_file != std::string::npos) {
6567 shorten_path = shorten_path.substr(last_file + 1);
6568 }
6569 return shorten_path;
6570}
6571
6572
6574 bounding_boxes_map.clear();
6575 int idx = 0;
6576 for (auto &box_pair: bounding_boxes) {
6577 if (box_pair.second) {
6578 bounding_boxes_map[box_pair.first] = idx;
6579 idx++;
6580 }
6581 }
6582 // std::vector<uint> all_UUIDs = context->getAllUUIDs();
6583 // context->clearPrimitiveData(all_UUIDs, "object_number");
6584 // for (auto &UUID : all_UUIDs){
6585 // if (!context->doesPrimitiveDataExist(UUID, "object_label")) continue;
6586 // std::string obj_label;
6587 // context->getPrimitiveData(UUID, "object_label", obj_label);
6588 // if (bounding_boxes_map.find(obj_label) != bounding_boxes_map.end()){
6589 // context->setPrimitiveData(UUID, "object_number", HELIOS_TYPE_UINT, 1, &bounding_boxes_map[obj_label]);
6590 // }
6591 // }
6592}
6593
6594
6595void ProjectBuilder::buildTiledGround(const vec3 &ground_origin, const vec2 &ground_extent, const int2 &texture_subtiles, const int2 &texture_subpatches, const char *ground_texture_file, float ground_rotation) {
6596 context->deletePrimitive(ground_UUIDs);
6597 if (context->doesObjectExist(ground_objID))
6598 context->deleteObject(ground_objID);
6599 ground_UUIDs.clear();
6600 primitive_UUIDs["ground"].clear();
6601
6602 vec2 dx_tile(ground_extent.x / float(texture_subtiles.x), ground_extent.y / float(texture_subtiles.y));
6603
6604 vec2 dx_subpatch(dx_tile.x / float(texture_subpatches.x), dx_tile.y / float(texture_subpatches.y));
6605
6606 std::vector<uint> UUIDs;
6607 for (int j = 0; j < texture_subtiles.y; j++) {
6608 for (int i = 0; i < texture_subtiles.x; i++) {
6609
6610 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);
6611
6612 if (ground_rotation != 0) {
6613 center = rotatePointAboutLine(center, ground_origin, make_vec3(0, 0, 1), ground_rotation);
6614 }
6615
6616 UUIDs = context->addTile(center, dx_tile, make_SphericalCoord(0, -ground_rotation), texture_subpatches, ground_texture_file);
6617
6618 ground_UUIDs.insert(ground_UUIDs.begin(), UUIDs.begin(), UUIDs.end());
6619 }
6620 }
6621 context->cleanDeletedUUIDs(ground_UUIDs);
6622
6623 context->setPrimitiveData(ground_UUIDs, "twosided_flag", uint(0));
6624 context->setGlobalData("ground_UUIDs", ground_UUIDs);
6625 context->setPrimitiveData(ground_UUIDs, "object_label", "ground");
6626 primitive_UUIDs["ground"] = ground_UUIDs;
6627}
6628
6629
6630void ProjectBuilder::buildTiledGround(const vec3 &ground_origin, const vec2 &ground_extent, const int2 &texture_subtiles, const int2 &texture_subpatches, RGBcolor ground_color, float ground_rotation) {
6631 context->deletePrimitive(ground_UUIDs);
6632 if (context->doesObjectExist(ground_objID))
6633 context->deleteObject(ground_objID);
6634 ground_UUIDs.clear();
6635 primitive_UUIDs["ground"].clear();
6636
6637 vec2 dx_tile(ground_extent.x / float(texture_subtiles.x), ground_extent.y / float(texture_subtiles.y));
6638
6639 vec2 dx_subpatch(dx_tile.x / float(texture_subpatches.x), dx_tile.y / float(texture_subpatches.y));
6640
6641 std::vector<uint> UUIDs;
6642 for (int j = 0; j < texture_subtiles.y; j++) {
6643 for (int i = 0; i < texture_subtiles.x; i++) {
6644
6645 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);
6646
6647 if (ground_rotation != 0) {
6648 center = rotatePointAboutLine(center, ground_origin, make_vec3(0, 0, 1), ground_rotation);
6649 }
6650
6651 UUIDs = context->addTile(center, dx_tile, make_SphericalCoord(0, -ground_rotation), texture_subpatches, ground_color);
6652
6653 ground_UUIDs.insert(ground_UUIDs.begin(), UUIDs.begin(), UUIDs.end());
6654 }
6655 }
6656 context->cleanDeletedUUIDs(ground_UUIDs);
6657
6658 context->setPrimitiveData(ground_UUIDs, "twosided_flag", uint(0));
6659 context->setGlobalData("ground_UUIDs", ground_UUIDs);
6660 context->setPrimitiveData(ground_UUIDs, "object_label", "ground");
6661 primitive_UUIDs["ground"] = ground_UUIDs;
6662}
6663
6664void ProjectBuilder::refreshBoundingBoxObjectList() {
6665 // Collect all unique primitive data labels
6666 std::set<std::string> primitive_data_labels;
6667 for (auto &primitive_UUID: context->getAllUUIDs()) {
6668 for (std::string data: context->listPrimitiveData(primitive_UUID)) {
6669 primitive_data_labels.insert(data);
6670 }
6671 }
6672 // Check data types for unique primitive labels
6673 for (const std::string &data: primitive_data_labels) {
6674 if (context->getPrimitiveDataType(data.c_str()) == HELIOS_TYPE_INT || context->getPrimitiveDataType(data.c_str()) == HELIOS_TYPE_UINT) {
6675 if (bounding_boxes.find(data) == bounding_boxes.end()) {
6676 bounding_boxes.insert({data, false});
6677 bounding_boxes_primitive.insert(data);
6678 }
6679 }
6680 }
6681
6682 // Collect all unique object data labels
6683 std::set<std::string> object_data_labels;
6684 for (auto &object_UUID: context->getAllObjectIDs()) {
6685 for (std::string data: context->listObjectData(object_UUID)) {
6686 object_data_labels.insert(data);
6687 }
6688 }
6689 // Check data types for unique object labels
6690 for (const std::string &data: object_data_labels) {
6691 if (context->getObjectDataType(data.c_str()) == HELIOS_TYPE_INT || context->getObjectDataType(data.c_str()) == HELIOS_TYPE_UINT) {
6692 if (bounding_boxes.find(data) == bounding_boxes.end()) {
6693 bounding_boxes.insert({data, false});
6694 bounding_boxes_object.insert(data);
6695 }
6696 }
6697 }
6698}
6699
6700
6701void ProjectBuilder::globalCalculation() {
6702 // Get all relevant primitives
6703 std::vector<uint> relevant_UUIDs{};
6704 if (calculation_selection_datagroup["All"]) {
6705 for (auto &prim_pair: primitive_UUIDs) {
6706 if (calculation_selection_primitive[prim_pair.first] || calculation_selection_primitive["All"]) {
6707 relevant_UUIDs.insert(relevant_UUIDs.end(), prim_pair.second.begin(), prim_pair.second.end());
6708 }
6709 }
6710 } else {
6711 for (auto &obj: objects_dict) {
6712 if (calculation_selection_datagroup[obj.second.data_group]) {
6713 for (auto &prim_pair: calculation_selection_primitive) {
6714 if (prim_pair.second || calculation_selection_primitive["All"]) {
6715 std::vector<uint> new_UUIDs = context->filterPrimitivesByData(obj.second.UUIDs, "object_label", prim_pair.first);
6716 relevant_UUIDs.insert(relevant_UUIDs.end(), new_UUIDs.begin(), new_UUIDs.end());
6717 }
6718 }
6719 }
6720 }
6721 for (auto &canopy: canopy_dict) {
6722 if (calculation_selection_datagroup[canopy.second.data_group]) {
6723 std::vector<uint> canopy_UUIDs;
6724 for (auto &plant_id: canopy.second.IDs) {
6725#ifdef ENABLE_PLANT_ARCHITECTURE
6726 std::vector<uint> plant_UUIDs = context->getObjectPrimitiveUUIDs(plantarchitecture->getAllPlantObjectIDs(plant_id));
6727 canopy_UUIDs.insert(canopy_UUIDs.end(), plant_UUIDs.begin(), plant_UUIDs.end());
6728#endif // PLANT_ARCHITECTURE
6729 }
6730 for (auto &prim_pair: calculation_selection_primitive) {
6731 if (prim_pair.second || calculation_selection_primitive["All"]) {
6732 std::vector<uint> new_UUIDs = context->filterPrimitivesByData(canopy_UUIDs, "object_label", prim_pair.first);
6733 relevant_UUIDs.insert(relevant_UUIDs.end(), new_UUIDs.begin(), new_UUIDs.end());
6734 }
6735 }
6736 }
6737 }
6738 }
6739 std::vector<std::string> globalVars = context->listGlobalData();
6740 // Perform calculation
6741 if (std::find(globalVars.begin(), globalVars.end(), calculation_variables_global[0]) != globalVars.end()) {
6742 context->getGlobalData(calculation_variables_global[0].c_str(), calculation_result_global);
6743 } else if (curr_aggregation == "Mean") {
6744 context->calculatePrimitiveDataMean(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6745 } else if (calculation_aggregations[0] == "Sum") {
6746 context->calculatePrimitiveDataSum(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6747 } else if (calculation_aggregations[0] == "Area Weighted Mean") {
6748 context->calculatePrimitiveDataAreaWeightedMean(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6749 } else if (calculation_aggregations[0] == "Area Weighted Sum") {
6750 context->calculatePrimitiveDataAreaWeightedSum(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6751 }
6752 for (int i = 0; i < calculation_operators_global.size(); i++) {
6753 float prev_res = calculation_result_global;
6754 if (calculation_aggregations[i] == "Mean") {
6755 context->calculatePrimitiveDataMean(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6756 } else if (calculation_aggregations[i] == "Sum") {
6757 context->calculatePrimitiveDataSum(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6758 } else if (calculation_aggregations[i] == "Area Weighted Mean") {
6759 context->calculatePrimitiveDataAreaWeightedMean(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6760 } else if (calculation_aggregations[i] == "Area Weighted Sum") {
6761 context->calculatePrimitiveDataAreaWeightedSum(relevant_UUIDs, calculation_variables_global[0], calculation_result_global);
6762 }
6763 std::string curr_op = calculation_operators_global[i];
6764 if (curr_op == "+") {
6765 calculation_result_global = prev_res + calculation_result_global;
6766 } else if (curr_op == "-") {
6767 calculation_result_global = prev_res - calculation_result_global;
6768 } else if (curr_op == "/") {
6769 calculation_result_global = prev_res / calculation_result_global;
6770 } else if (curr_op == "x") {
6771 calculation_result_global = prev_res * calculation_result_global;
6772 }
6773 }
6774}
6775
6776
6777void ProjectBuilder::savePrimitiveCalculation() {
6778 // Get all relevant primitives
6779 std::vector<uint> relevant_UUIDs{};
6780 if (calculation_selection_datagroup["All"]) {
6781 for (auto &prim_pair: primitive_UUIDs) {
6782 if (calculation_selection_primitive[prim_pair.first] || calculation_selection_primitive["All"]) {
6783 relevant_UUIDs.insert(relevant_UUIDs.end(), prim_pair.second.begin(), prim_pair.second.end());
6784 }
6785 }
6786 } else {
6787 for (auto &obj: objects_dict) {
6788 if (calculation_selection_datagroup[obj.second.data_group]) {
6789 for (auto &prim_pair: calculation_selection_primitive) {
6790 if (prim_pair.second || calculation_selection_primitive["All"]) {
6791 std::vector<uint> new_UUIDs = context->filterPrimitivesByData(obj.second.UUIDs, "object_label", prim_pair.first);
6792 relevant_UUIDs.insert(relevant_UUIDs.end(), new_UUIDs.begin(), new_UUIDs.end());
6793 }
6794 }
6795 }
6796 }
6797 for (auto &canopy: canopy_dict) {
6798 if (calculation_selection_datagroup[canopy.second.data_group]) {
6799 std::vector<uint> canopy_UUIDs;
6800 for (auto &plant_id: canopy.second.IDs) {
6801#ifdef ENABLE_PLANT_ARCHITECTURE
6802 std::vector<uint> plant_UUIDs = context->getObjectPrimitiveUUIDs(plantarchitecture->getAllPlantObjectIDs(plant_id));
6803 canopy_UUIDs.insert(canopy_UUIDs.end(), plant_UUIDs.begin(), plant_UUIDs.end());
6804#endif // PLANT_ARCHITECTURE
6805 }
6806 for (auto &prim_pair: calculation_selection_primitive) {
6807 if (prim_pair.second || calculation_selection_primitive["All"]) {
6808 std::vector<uint> new_UUIDs = context->filterPrimitivesByData(canopy_UUIDs, "object_label", prim_pair.first);
6809 relevant_UUIDs.insert(relevant_UUIDs.end(), new_UUIDs.begin(), new_UUIDs.end());
6810 }
6811 }
6812 }
6813 }
6814 }
6815 for (auto &UUID: relevant_UUIDs) {
6816 context->setPrimitiveData(UUID, calculation_name_primitive.c_str(), calculation_result_global);
6817 }
6818 refreshVisualizationTypes();
6819}
6820
6821
6822void ProjectBuilder::runRadiation() {
6823#ifdef ENABLE_RADIATION_MODEL
6824 for (std::string band_group_name: band_group_names) {
6825 bandGroup curr_band_group = band_group_lookup[band_group_name];
6826 if (!curr_band_group.grayscale) {
6827 radiation->runBand(curr_band_group.bands);
6828 } else {
6829 radiation->runBand(std::vector<std::string>{curr_band_group.bands[0]});
6830 }
6831 }
6832#endif // RADIATION_MODEL
6833}