18using namespace helios;
22 install_out_of_memory_handler();
34 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
45 currentMaterialID = 0;
49 materials[0] = default_material;
50 material_label_to_id[DEFAULT_MATERIAL_LABEL] = 0;
51 currentMaterialID = 1;
69void Context::addTexture(
const char *texture_file) {
70 if (textures.find(texture_file) == textures.end()) {
73 const std::string &fn = texture_file;
75 if (ext !=
".png" && ext !=
".PNG" && ext !=
".jpg" && ext !=
".jpeg" && ext !=
".JPG" && ext !=
".JPEG") {
76 helios_runtime_error(
"ERROR (Context::addTexture): Texture file " + fn +
" is not PNG or JPEG format.");
77 }
else if (!doesTextureFileExist(texture_file)) {
78 helios_runtime_error(
"ERROR (Context::addTexture): Texture file " + std::string(texture_file) +
" does not exist.");
83 textures.emplace(texture_file,
Texture(resolved_path.string().c_str()));
87bool Context::doesTextureFileExist(
const char *texture_file)
const {
90 return std::filesystem::exists(resolved_path);
91 }
catch (
const std::runtime_error &) {
96bool Context::validateTextureFileExtenstion(
const char *texture_file)
const {
97 const std::string &fn = texture_file;
99 if (ext !=
".png" && ext !=
".PNG" && ext !=
".jpg" && ext !=
".jpeg" && ext !=
".JPG" && ext !=
".JPEG") {
107 filename = texture_file;
114 hastransparencychannel =
false;
116 hastransparencychannel =
PNGHasAlpha(filename.c_str());
123 image_resolution =
make_int2(
int(transparencydata.front().size()),
int(transparencydata.size()));
130 if (hastransparencychannel) {
132 for (
auto &j: transparencydata) {
133 for (
bool transparency: j) {
139 float sf = float(p) / float(transparencydata.size() * transparencydata.front().size());
140 if (std::isnan(sf)) {
154 return image_resolution;
158 return hastransparencychannel;
162 return &transparencydata;
166 float solidfraction = 1;
169 key.coords.reserve(2 * uvs.size());
170 for (
auto &uvc: uvs) {
171 key.coords.push_back(
int(std::round(uvc.x * (image_resolution.
x - 1))));
172 key.coords.push_back(
int(std::round(uvc.y * (image_resolution.
y - 1))));
175 if (solidFracCache.find(key) != solidFracCache.end()) {
176 return solidFracCache.at(key);
179 solidfraction = computeSolidFraction(uvs);
180 solidFracCache.emplace(std::move(key), solidfraction);
182 return solidfraction;
185float Texture::computeSolidFraction(
const std::vector<helios::vec2> &uvs)
const {
197 std::vector<uint8_t> mask(W * H);
198 for (
int y = 0; y < H; ++y)
199 for (
int x = 0; x < W; ++x)
200 mask[y * W + x] = (*alpha2D)[H - 1 - y][x];
203 float minU = uvs[0].x, maxU = uvs[0].x, minV = uvs[0].y, maxV = uvs[0].y;
205 minU = std::min(minU, p.x);
206 maxU = std::max(maxU, p.x);
207 minV = std::min(minV, p.y);
208 maxV = std::max(maxV, p.y);
210 int xmin = std::clamp(
int(std::floor(minU * (W - 1))), 0, W - 1);
211 int xmax = std::clamp(
int(std::ceil(maxU * (W - 1))), 0, W - 1);
212 int ymin = std::clamp(
int(std::floor(minV * (H - 1))), 0, H - 1);
213 int ymax = std::clamp(
int(std::ceil(maxV * (H - 1))), 0, H - 1);
215 if (xmin > xmax || ymin > ymax)
219 int N = int(uvs.size());
220 std::vector<float> A(N), B(N), C(N);
221 for (
int i = 0; i < N; ++i) {
223 const auto &a = uvs[i], &b = uvs[j];
227 C[i] = a.x * b.y - a.y * b.x;
232 float signed_area = 0.0f;
233 for (
int i = 0; i < N; ++i) {
235 signed_area += uvs[i].x * uvs[j].y - uvs[j].x * uvs[i].y;
237 if (signed_area < 0.0f) {
239 for (
int i = 0; i < N; ++i) {
247 int64_t countTotal = 0, countOpaque = 0;
248 float invWm1 = 1.0f / float(W - 1);
249 float invHm1 = 1.0f / float(H - 1);
251 for (
int j = ymin; j <= ymax; ++j) {
252 float yuv = (j + 0.5f) * invHm1;
253 for (
int i = xmin; i <= xmax; ++i) {
254 float xuv = (i + 0.5f) * invWm1;
258 for (
int k = 0; k < N; ++k) {
259 float L = A[k] * yuv + B[k] * xuv + C[k];
270 countOpaque += mask[j * W + i];
274 float result = countTotal == 0 ? 0.0f : float(countOpaque) / float(countTotal);
279 for (
auto &[UUID, primitive]: primitives) {
280 primitive->dirty_flag =
false;
282 dirty_deleted_primitives.clear();
286 for (
auto &[UUID, primitive]: primitives) {
287 primitive->dirty_flag =
true;
292 if (!dirty_deleted_primitives.empty()) {
295 for (
auto &[UUID, primitive]: primitives) {
296 if (primitive->dirty_flag) {
306 helios_runtime_error(
"ERROR (Context::markPrimitiveDirty): Primitive with UUID " + std::to_string(UUID) +
" does not exist.");
309 primitives.at(UUID)->dirty_flag =
true;
313 for (
uint UUID: UUIDs) {
321 helios_runtime_error(
"ERROR (Context::markPrimitiveDirty): Primitive with UUID " + std::to_string(UUID) +
" does not exist.");
324 primitives.at(UUID)->dirty_flag =
false;
328 for (
uint UUID: UUIDs) {
336 helios_runtime_error(
"ERROR (Context::markPrimitiveDirty): Primitive with UUID " + std::to_string(UUID) +
" does not exist.");
339 return primitives.at(UUID)->dirty_flag;
344 if (day < 1 || day > 31) {
345 helios_runtime_error(
"ERROR (Context::setDate): Day of month is out of range (day of " + std::to_string(day) +
" was given).");
346 }
else if (month < 1 || month > 12) {
347 helios_runtime_error(
"ERROR (Context::setDate): Month of year is out of range (month of " + std::to_string(month) +
" was given).");
348 }
else if (year < 1000) {
356 if (date.day < 1 || date.day > 31) {
357 helios_runtime_error(
"ERROR (Context::setDate): Day of month is out of range (day of " + std::to_string(date.day) +
" was given).");
358 }
else if (date.month < 1 || date.month > 12) {
359 helios_runtime_error(
"ERROR (Context::setDate): Month of year is out of range (month of " + std::to_string(date.month) +
" was given).");
360 }
else if (date.year < 1000) {
368 if (Julian_day < 1 || Julian_day > 366) {
370 }
else if (year < 1000) {
382 if (sim_date.
month == 1) {
384 }
else if (sim_date.
month == 2) {
386 }
else if (sim_date.
month == 3) {
388 }
else if (sim_date.
month == 4) {
390 }
else if (sim_date.
month == 5) {
392 }
else if (sim_date.
month == 6) {
394 }
else if (sim_date.
month == 7) {
396 }
else if (sim_date.
month == 8) {
398 }
else if (sim_date.
month == 9) {
400 }
else if (sim_date.
month == 10) {
402 }
else if (sim_date.
month == 11) {
418 if (second < 0 || second > 59) {
420 }
else if (minute < 0 || minute > 59) {
422 }
else if (hour < 0 || hour > 23) {
426 sim_time =
make_Time(hour, minute, second);
430 if (time.minute < 0 || time.minute > 59) {
432 }
else if (time.hour < 0 || time.hour > 23) {
444 sim_location = location;
452 return unif_distribution(generator);
456 if (maxrange < minrange) {
457 helios_runtime_error(
"ERROR (Context::randu): Maximum value of range must be greater than minimum value of range.");
459 }
else if (maxrange == minrange) {
462 return minrange + unif_distribution(generator) * (maxrange - minrange);
467 if (maxrange < minrange) {
468 helios_runtime_error(
"ERROR (Context::randu): Maximum value of range must be greater than minimum value of range.");
470 }
else if (maxrange == minrange) {
473 return minrange + (int) lroundf(unif_distribution(generator) * float(maxrange - minrange));
478 return norm_distribution(generator);
482 return mean + norm_distribution(generator) * fabs(stddev);
488 if (all_uuids_cache_valid) {
489 return cached_all_uuids;
493 cached_all_uuids.clear();
494 cached_all_uuids.reserve(primitives.size());
495 for (
const auto &[UUID, primitive]: primitives) {
496 if (primitive->ishidden) {
499 cached_all_uuids.push_back(UUID);
502 all_uuids_cache_valid =
true;
503 return cached_all_uuids;
508 size_t dirty_count = std::count_if(primitives.begin(), primitives.end(), [&](
auto const &kv) { return isPrimitiveDirty(kv.first); });
510 std::vector<uint> dirty_UUIDs;
511 dirty_UUIDs.reserve(dirty_count);
512 for (
const auto &[UUID, primitive]: primitives) {
513 if (!primitive->dirty_flag || primitive->ishidden) {
516 dirty_UUIDs.push_back(UUID);
519 if (include_deleted_UUIDs) {
520 dirty_UUIDs.insert(dirty_UUIDs.end(), dirty_deleted_primitives.begin(), dirty_deleted_primitives.end());
527 return dirty_deleted_primitives;
533 helios_runtime_error(
"ERROR (Context::hidePrimitive): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
536 primitives.at(UUID)->ishidden =
true;
537 invalidateAllUUIDsCache();
541 for (
uint UUID: UUIDs) {
549 helios_runtime_error(
"ERROR (Context::showPrimitive): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
552 primitives.at(UUID)->ishidden =
false;
553 invalidateAllUUIDsCache();
557 for (
uint UUID: UUIDs) {
564 helios_runtime_error(
"ERROR (Context::isPrimitiveHidden): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
566 return primitives.at(UUID)->ishidden;
570 for (
size_t i = UUIDs.size(); i-- > 0;) {
572 UUIDs.erase(UUIDs.begin() + i);
578 for (
auto &vec: UUIDs) {
579 for (
auto it = vec.begin(); it != vec.end();) {
590 for (
auto &vec2D: UUIDs) {
591 for (
auto &vec: vec2D) {
592 for (
auto it = vec.begin(); it != vec.end();) {
605 double date_value = floor(date.year * 366.25) + date.JulianDay();
606 date_value += double(time.hour) / 24. + double(time.minute) / 1440. + double(time.second) / 86400.;
609 if (timeseries_data.find(label) == timeseries_data.end()) {
610 timeseries_data[label].push_back(value);
611 timeseries_datevalue[label].push_back(date_value);
617 auto it_data = timeseries_data[label].begin();
618 auto it_datevalue = timeseries_datevalue[label].begin();
621 if (date_value < timeseries_datevalue[label].front()) {
622 timeseries_data[label].insert(it_data, value);
623 timeseries_datevalue[label].insert(it_datevalue, date_value);
626 timeseries_data[label].insert(it_data + 1, value);
627 timeseries_datevalue[label].insert(it_datevalue + 1, date_value);
631 if (date_value < timeseries_datevalue[label].front()) {
632 timeseries_data[label].insert(it_data, value);
633 timeseries_datevalue[label].insert(it_datevalue, date_value);
635 }
else if (date_value > timeseries_datevalue[label].back()) {
636 timeseries_data[label].push_back(value);
637 timeseries_datevalue[label].push_back(date_value);
642 for (
uint t = 0; t < N - 1; t++) {
643 if (date_value == timeseries_datevalue[label].at(t)) {
644 std::cerr <<
"WARNING (Context::addTimeseriesData): Skipping duplicate timeseries date/time." << std::endl;
647 if (date_value > timeseries_datevalue[label].at(t) && date_value < timeseries_datevalue[label].at(t + 1)) {
648 timeseries_data[label].insert(it_data + t + 1, value);
649 timeseries_datevalue[label].insert(it_datevalue + t + 1, date_value);
656 helios_runtime_error(
"ERROR (Context::addTimeseriesData): Failed to insert timeseries data for unknown reason.");
660 if (timeseries_data.find(label) == timeseries_data.end()) {
661 helios_runtime_error(
"ERROR (Context::updateTimeseriesData): Timeseries variable `" + std::string(label) +
"' does not exist.");
664 double date_value = floor(date.year * 366.25) + date.JulianDay();
665 date_value += double(time.hour) / 24. + double(time.minute) / 1440. + double(time.second) / 86400.;
667 const std::vector<double> &datevalues = timeseries_datevalue.at(label);
668 for (
uint i = 0; i < datevalues.size(); i++) {
669 if (datevalues.at(i) == date_value) {
670 timeseries_data.at(label).at(i) = new_value;
675 helios_runtime_error(
"ERROR (Context::updateTimeseriesData): No timeseries data point exists at the specified date and time for variable `" + std::string(label) +
"'.");
679 if (timeseries_data.find(label) == timeseries_data.end()) {
680 helios_runtime_error(
"ERROR (setCurrentTimeseriesPoint): Timeseries variable `" + std::string(label) +
"' does not exist.");
687 if (timeseries_data.find(label) == timeseries_data.end()) {
688 helios_runtime_error(
"ERROR (setCurrentTimeseriesData): Timeseries variable `" + std::string(label) +
"' does not exist.");
691 double date_value = floor(date.year * 366.25) + date.JulianDay();
692 date_value += double(time.hour) / 24. + double(time.minute) / 1440. + double(time.second) / 86400.;
694 double tmin = timeseries_datevalue.at(label).front();
695 double tmax = timeseries_datevalue.at(label).back();
697 if (date_value < tmin) {
698 std::cerr <<
"WARNING (queryTimeseriesData): Timeseries date and time is outside of the range of the data. Using the earliest data point in the timeseries." << std::endl;
699 return timeseries_data.at(label).front();
700 }
else if (date_value > tmax) {
701 std::cerr <<
"WARNING (queryTimeseriesData): Timeseries date and time is outside of the range of the data. Using the latest data point in the timeseries." << std::endl;
702 return timeseries_data.at(label).back();
705 if (timeseries_datevalue.at(label).empty()) {
706 std::cerr <<
"WARNING (queryTimeseriesData): timeseries " << label <<
" does not contain any data." << std::endl;
708 }
else if (timeseries_datevalue.at(label).size() == 1) {
709 return timeseries_data.at(label).front();
712 bool success =
false;
713 for (i = 0; i < timeseries_data.at(label).size() - 1; i++) {
714 if (date_value >= timeseries_datevalue.at(label).at(i) && date_value <= timeseries_datevalue.at(label).at(i + 1)) {
721 helios_runtime_error(
"ERROR (queryTimeseriesData): Failed to query timeseries data for unknown reason.");
724 double xminus = timeseries_data.at(label).at(i);
725 double xplus = timeseries_data.at(label).at(i + 1);
727 double tminus = timeseries_datevalue.at(label).at(i);
728 double tplus = timeseries_datevalue.at(label).at(i + 1);
730 return float(xminus + (xplus - xminus) * (date_value - tminus) / (tplus - tminus));
739 if (timeseries_data.find(label) == timeseries_data.end()) {
740 helios_runtime_error(
"ERROR( Context::getTimeseriesData): Timeseries variable " + std::string(label) +
" does not exist.");
743 return timeseries_data.at(label).at(index);
747 if (timeseries_data.find(label) == timeseries_data.end()) {
748 helios_runtime_error(
"ERROR( Context::getTimeseriesTime): Timeseries variable " + std::string(label) +
" does not exist.");
751 double dateval = timeseries_datevalue.at(label).at(index);
753 int year = floor(floor(dateval) / 366.25);
754 assert(year > 1000 && year < 10000);
756 int JD = floor(dateval - floor(
double(year) * 366.25));
757 assert(JD > 0 && JD < 367);
759 int hour = floor((dateval - floor(dateval)) * 24.);
760 int minute = floor(((dateval - floor(dateval)) * 24. -
double(hour)) * 60.);
761 int second = (int) lround((((dateval - floor(dateval)) * 24. -
double(hour)) * 60. -
double(minute)) * 60.);
773 assert(second >= 0 && second < 60);
774 assert(minute >= 0 && minute < 60);
775 assert(hour >= 0 && hour < 24);
781 if (timeseries_data.find(label) == timeseries_data.end()) {
782 helios_runtime_error(
"ERROR( Context::getTimeseriesDate): Timeseries variable " + std::string(label) +
" does not exist.");
785 double dateval = timeseries_datevalue.at(label).at(index);
787 int year = floor(floor(dateval) / 366.25);
788 assert(year > 1000 && year < 10000);
790 int JD = floor(dateval - floor(
double(year) * 366.25));
791 assert(JD > 0 && JD < 367);
798 if (timeseries_data.find(label) == timeseries_data.end()) {
799 helios_runtime_error(
"ERROR (Context::getTimeseriesDate): Timeseries variable `" + std::string(label) +
"' does not exist.");
801 size = timeseries_data.at(label).size();
808 if (timeseries_data.find(label) == timeseries_data.end()) {
816 std::vector<std::string> labels;
817 labels.reserve(timeseries_data.size());
818 for (
const auto &[timeseries_label, timeseries_data]: timeseries_data) {
819 labels.push_back(timeseries_label);
825 timeseries_data.clear();
826 timeseries_datevalue.clear();
830 auto it = timeseries_data.find(label);
831 if (it == timeseries_data.end()) {
832 std::cerr <<
"WARNING (Context::deleteTimeseriesVariable): Timeseries variable '" << label <<
"' does not exist. Nothing to delete." << std::endl;
835 timeseries_data.erase(it);
836 timeseries_datevalue.erase(label);
840 auto it_data = timeseries_data.find(label);
841 auto it_datevalue = timeseries_datevalue.find(label);
842 if (it_data == timeseries_data.end() || it_datevalue == timeseries_datevalue.end()) {
843 std::cerr <<
"WARNING (Context::deleteTimeseriesDataPoint): Timeseries variable '" << label <<
"' does not exist. Nothing to delete." << std::endl;
847 double date_value = floor(date.year * 366.25) + date.JulianDay();
848 date_value += double(time.hour) / 24. + double(time.minute) / 1440. + double(time.second) / 86400.;
850 std::vector<double> &datevalues = it_datevalue->second;
851 std::vector<float> &values = it_data->second;
852 for (
size_t i = 0; i < datevalues.size(); i++) {
853 if (datevalues[i] == date_value) {
854 datevalues.erase(datevalues.begin() + i);
855 values.erase(values.begin() + i);
860 std::cerr <<
"WARNING (Context::deleteTimeseriesDataPoint): No timeseries data point exists at the specified date and time for variable '" << label <<
"'. Nothing to delete." << std::endl;
864 double date_value = floor(date.year * 366.25) + date.JulianDay();
865 date_value += double(time.hour) / 24. + double(time.minute) / 1440. + double(time.second) / 86400.;
867 bool any_match =
false;
868 for (
auto &[label, datevalues]: timeseries_datevalue) {
869 std::vector<float> &values = timeseries_data.at(label);
870 for (
size_t i = 0; i < datevalues.size(); i++) {
871 if (datevalues[i] == date_value) {
872 datevalues.erase(datevalues.begin() + i);
873 values.erase(values.begin() + i);
881 std::cerr <<
"WARNING (Context::deleteTimeseriesDataPoint): No timeseries variable contains a data point at the specified date and time. Nothing to delete." << std::endl;
903 float local_xmin = 1e8, local_xmax = -1e8;
904 float local_ymin = 1e8, local_ymax = -1e8;
905 float local_zmin = 1e8, local_zmax = -1e8;
908#pragma omp for nowait
909 for (
int i = 0; i < (int) UUIDs.size(); i++) {
911 const std::vector<vec3> &verts = getPrimitivePointer_private(UUIDs[i])->getVertices();
913 for (
const auto &vert: verts) {
914 local_xmin = std::min(local_xmin, vert.x);
915 local_xmax = std::max(local_xmax, vert.x);
916 local_ymin = std::min(local_ymin, vert.y);
917 local_ymax = std::max(local_ymax, vert.y);
918 local_zmin = std::min(local_zmin, vert.z);
919 local_zmax = std::max(local_zmax, vert.z);
926 xbounds.
x = std::min(xbounds.
x, local_xmin);
927 xbounds.
y = std::max(xbounds.
y, local_xmax);
928 ybounds.
x = std::min(ybounds.
x, local_ymin);
929 ybounds.
y = std::max(ybounds.
y, local_ymax);
930 zbounds.
x = std::min(zbounds.
x, local_zmin);
931 zbounds.
y = std::max(zbounds.
y, local_zmax);
937 for (
uint UUID: UUIDs) {
938 const std::vector<vec3> &verts = getPrimitivePointer_private(UUID)->getVertices();
940 for (
auto &vert: verts) {
941 if (vert.x < xbounds.
x) {
943 }
else if (vert.x > xbounds.
y) {
946 if (vert.y < ybounds.
x) {
948 }
else if (vert.y > ybounds.
y) {
951 if (vert.z < zbounds.
x) {
953 }
else if (vert.z > zbounds.
y) {
963 vec2 xbounds, ybounds, zbounds;
966 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
967 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
968 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
970 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
974 vec2 xbounds, ybounds, zbounds;
977 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
978 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
979 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
981 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
985 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
987 for (
uint p: UUIDs_all) {
988 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
990 for (
auto &vertex: vertices) {
991 if (vertex.x < xbounds.
x || vertex.x > xbounds.
y) {
999 std::cerr <<
"WARNING (Context::cropDomainX): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
1004 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
1006 for (
uint p: UUIDs_all) {
1007 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
1009 for (
auto &vertex: vertices) {
1010 if (vertex.y < ybounds.
x || vertex.y > ybounds.
y) {
1018 std::cerr <<
"WARNING (Context::cropDomainY): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
1023 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
1025 for (
uint p: UUIDs_all) {
1026 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
1028 for (
auto &vertex: vertices) {
1029 if (vertex.z < zbounds.
x || vertex.z > zbounds.
y) {
1037 std::cerr <<
"WARNING (Context::cropDomainZ): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
1042 size_t delete_count = 0;
1043 for (
uint UUID: UUIDs) {
1044 const std::vector<vec3> &vertices = getPrimitivePointer_private(UUID)->getVertices();
1046 for (
auto &vertex: vertices) {
1047 if (vertex.x < xbounds.
x || vertex.x > xbounds.
y || vertex.y < ybounds.
x || vertex.y > ybounds.
y || vertex.z < zbounds.
x || vertex.z > zbounds.
y) {
1055 if (delete_count == UUIDs.size()) {
1056 std::cerr <<
"WARNING (Context::cropDomain): No specified primitives were entirely inside cropped area, and thus all specified primitives were deleted." << std::endl;
1064 cropDomain(UUIDs, xbounds, ybounds, zbounds);
1071 helios_runtime_error(
"ERROR (Context::areObjectPrimitivesComplete): Object ID of " + std::to_string(objID) +
" does not exist in the context.");
1078 for (
auto it = objIDs.begin(); it != objIDs.end();) {
1080 it = objIDs.erase(it);
1088 for (
auto &vec: objIDs) {
1089 for (
auto it = vec.begin(); it != vec.end();) {
1100 for (
auto &vec2D: objIDs) {
1101 for (
auto &vec: vec2D) {
1102 for (
auto it = vec.begin(); it != vec.end();) {
1114 return objects.size();
1118 return objects.find(ObjID) != objects.end();
1122 std::vector<uint> objIDs;
1123 objIDs.reserve(objects.size());
1125 for (
auto [objID,
object]: objects) {
1129 objIDs.push_back(objID);
1136 for (
const uint ObjID: ObjIDs) {
1142 if (objects.find(ObjID) == objects.end()) {
1143 helios_runtime_error(
"ERROR (Context::deleteObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1148 for (
const auto &[label, type]:
obj->object_data_types) {
1149 decrementObjectDataLabelCounter(label);
1152 const std::vector<uint> &UUIDs =
obj->getPrimitiveUUIDs();
1156 objects.erase(ObjID);
1162 std::vector<uint> ObjIDs_copy(ObjIDs.size());
1164 for (
uint ObjID: ObjIDs) {
1173 if (objects.find(ObjID) == objects.end()) {
1174 helios_runtime_error(
"ERROR (Context::copyObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1177 ObjectType type = objects.at(ObjID)->getObjectType();
1179 const std::vector<uint> &UUIDs = getObjectPointer_private(ObjID)->
getPrimitiveUUIDs();
1182 for (
uint p: UUIDs_copy) {
1183 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1186 const std::string &texturefile = objects.at(ObjID)->getTextureFile();
1189 Tile *o = getTileObjectPointer_private(ObjID);
1193 auto *tile_new = (
new Tile(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1195 objects[currentObjectID] = tile_new;
1197 Sphere *o = getSphereObjectPointer_private(ObjID);
1201 auto *sphere_new = (
new Sphere(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1203 objects[currentObjectID] = sphere_new;
1205 Tube *o = getTubeObjectPointer_private(ObjID);
1207 const std::vector<vec3> &nodes = o->
getNodes();
1213 auto *tube_new = (
new Tube(currentObjectID, UUIDs_copy, nodes, radius, colors, triangle_vertices, subdiv, texturefile.c_str(),
this));
1215 objects[currentObjectID] = tube_new;
1217 Box *o = getBoxObjectPointer_private(ObjID);
1221 auto *box_new = (
new Box(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1223 objects[currentObjectID] = box_new;
1225 Disk *o = getDiskObjectPointer_private(ObjID);
1229 auto *disk_new = (
new Disk(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1231 objects[currentObjectID] = disk_new;
1233 auto *polymesh_new = (
new Polymesh(currentObjectID, UUIDs_copy, texturefile.c_str(),
this));
1235 objects[currentObjectID] = polymesh_new;
1237 Cone *o = getConeObjectPointer_private(ObjID);
1243 auto *cone_new = (
new Cone(currentObjectID, UUIDs_copy, nodes.at(0), nodes.at(1), radius.at(0), radius.at(1), subdiv, texturefile.c_str(),
this));
1245 objects[currentObjectID] = cone_new;
1256 return currentObjectID - 1;
1260 std::vector<uint> output_object_IDs;
1261 output_object_IDs.resize(IDs.size());
1262 uint passed_count = 0;
1266 for (
uint i = 0; i < IDs.size(); i++) {
1272 if (strcmp(comparator,
"<") == 0) {
1273 if (
float(
R) < threshold) {
1274 output_object_IDs.at(passed_count) = IDs.at(i);
1277 }
else if (strcmp(comparator,
">") == 0) {
1278 if (
float(
R) > threshold) {
1279 output_object_IDs.at(passed_count) = IDs.at(i);
1282 }
else if (strcmp(comparator,
"=") == 0) {
1283 if (
float(
R) == threshold) {
1284 output_object_IDs.at(passed_count) = IDs.at(i);
1292 if (strcmp(comparator,
"<") == 0) {
1293 if (
R < threshold) {
1294 output_object_IDs.at(passed_count) = IDs.at(i);
1297 }
else if (strcmp(comparator,
">") == 0) {
1298 if (
R > threshold) {
1299 output_object_IDs.at(passed_count) = IDs.at(i);
1302 }
else if (strcmp(comparator,
"=") == 0) {
1303 if (
R == threshold) {
1304 output_object_IDs.at(passed_count) = IDs.at(i);
1312 if (strcmp(comparator,
"<") == 0) {
1313 if (
float(
R) < threshold) {
1314 output_object_IDs.at(passed_count) = IDs.at(i);
1317 }
else if (strcmp(comparator,
">") == 0) {
1318 if (
float(
R) > threshold) {
1319 output_object_IDs.at(passed_count) = IDs.at(i);
1322 }
else if (strcmp(comparator,
"=") == 0) {
1323 if (
float(
R) == threshold) {
1324 output_object_IDs.at(passed_count) = IDs.at(i);
1329 warnings.
addWarning(
"object_data_wrong_type",
"Object data not of type UINT, INT, or FLOAT. Filtering for other types not yet supported.");
1334 warnings.
report(std::cerr);
1336 output_object_IDs.resize(passed_count);
1338 return output_object_IDs;
1344 helios_runtime_error(
"ERROR (Context::translateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1347 getObjectPointer_private(ObjID)->
translate(shift);
1351 for (
uint ID: ObjIDs) {
1359 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1362 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_xyz);
1365void Context::rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const char *rotation_axis_xyz)
const {
1366 for (
uint ID: ObjIDs) {
1374 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1377 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_vector);
1381 for (
uint ID: ObjIDs) {
1382 rotateObject(ID, rotation_radians, rotation_axis_vector);
1389 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1392 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_origin, rotation_axis_vector);
1396 for (
uint ID: ObjIDs) {
1397 rotateObject(ID, rotation_radians, rotation_origin, rotation_axis_vector);
1404 helios_runtime_error(
"ERROR (Context::rotateObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1407 getObjectPointer_private(ObjID)->
rotate(rotation_radians, objects.at(ObjID)->object_origin, rotation_axis_vector);
1411 for (
uint ID: ObjIDs) {
1412 rotateObject(ID, rotation_radians, objects.at(ID)->object_origin, rotation_axis_vector);
1419 helios_runtime_error(
"ERROR (Context::scaleObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1422 getObjectPointer_private(ObjID)->
scale(scalefact);
1426 for (
uint ID: ObjIDs) {
1434 helios_runtime_error(
"ERROR (Context::scaleObjectAboutCenter): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1441 for (
uint ID: ObjIDs) {
1449 helios_runtime_error(
"ERROR (Context::scaleObjectAboutPoint): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1456 for (
uint ID: ObjIDs) {
1464 helios_runtime_error(
"ERROR (Context::scaleObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1467 getObjectPointer_private(ObjID)->
scaleAboutPoint(scalefact, objects.at(ObjID)->object_origin);
1471 for (
uint ID: ObjIDs) {
1479 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1485 std::vector<uint> UUIDs;
1489 UUIDs.push_back(UUID);
1499 std::vector<uint> output_UUIDs;
1501 for (
uint ObjID: ObjIDs) {
1504 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1508 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1510 return output_UUIDs;
1514 std::vector<uint> output_UUIDs;
1516 for (
uint j = 0; j < ObjIDs.size(); j++) {
1517 for (
uint i = 0; i < ObjIDs.at(j).size(); i++) {
1520 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjIDs.at(j).at(i)) +
" not found in the context.");
1524 const std::vector<uint> ¤t_UUIDs = getObjectPointer_private(ObjIDs.at(j).at(i))->
getPrimitiveUUIDs();
1525 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1528 return output_UUIDs;
1537 helios_runtime_error(
"ERROR (Context::getObjectType): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1546 helios_runtime_error(
"ERROR (Context::getTileObjectAreaRatio): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1550 std::cerr <<
"WARNING (Context::getTileObjectAreaRatio): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1554 if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1555 std::cerr <<
"WARNING (Context::getTileObjectAreaRatio): ObjectID " << ObjID <<
" is missing primitives. Area ratio calculated is area of non-missing subpatches divided by the area of an individual subpatch." << std::endl;
1559 if (subdiv.
x == 1 && subdiv.
y == 1) {
1563 float area = getTileObjectPointer_private(ObjID)->
getArea();
1564 const vec2 size = getTileObjectPointer_private(ObjID)->
getSize();
1566 float subpatch_area = size.
x * size.
y / scast<float>(subdiv.
x * subdiv.
y);
1567 return area / subpatch_area;
1571 std::vector<float> AreaRatios(ObjIDs.size());
1572 for (
uint i = 0; i < ObjIDs.size(); i++) {
1579void Context::regenerateTileObjectSubpatches(
uint ObjID,
const int2 &new_subdiv) {
1580 Tile *tile = getTileObjectPointer_private(ObjID);
1592 Patch *first_patch = getPatchPointer_private(UUIDs_old.front());
1593 const bool textured = first_patch->hasTexture();
1596 uint template_ObjID;
1606 const std::vector<uint> template_UUIDs = getTileObjectPointer_private(template_ObjID)->
getPrimitiveUUIDs();
1608 std::vector<uint> UUIDs_new =
copyPrimitive(template_UUIDs);
1612 for (
uint UUID: UUIDs_new) {
1616 getPrimitivePointer_private(UUID)->setParentObjectID(ObjID);
1624 bool any_old_has_data =
false;
1625 for (
uint UUID: UUIDs_old) {
1627 any_old_has_data =
true;
1631 if (any_old_has_data) {
1632 for (
size_t k = 0; k < UUIDs_new.size(); k++) {
1634 const float u = canonical_center.
x + 0.5f;
1635 const float v = canonical_center.
y + 0.5f;
1636 int old_i =
static_cast<int>(std::floor(u * scast<float>(old_subdiv.
x)));
1637 int old_j =
static_cast<int>(std::floor(v * scast<float>(old_subdiv.
y)));
1638 old_i = std::max(0, std::min(old_subdiv.
x - 1, old_i));
1639 old_j = std::max(0, std::min(old_subdiv.
y - 1, old_j));
1640 const size_t old_index = scast<size_t>(old_j) * scast<size_t>(old_subdiv.
x) + scast<size_t>(old_i);
1657 std::vector<uint> tile_ObjectIDs;
1660 for (
uint ObjID: ObjIDs) {
1663 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1668 warnings.
addWarning(
"not_a_tile_object",
"ObjectID " + std::to_string(ObjID) +
" is not a tile object. Skipping...");
1669 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1670 warnings.
addWarning(
"tile_object_missing_primitives",
"ObjectID " + std::to_string(ObjID) +
" is missing primitives. Skipping...");
1672 tile_ObjectIDs.push_back(ObjID);
1676 warnings.
report(std::cerr);
1679 for (
uint tile_ObjectID: tile_ObjectIDs) {
1680 regenerateTileObjectSubpatches(tile_ObjectID, new_subdiv);
1686 if (area_ratio < 1.f) {
1687 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Area ratio must be greater than or equal to 1 (it is the ratio of the whole tile area to an individual sub-patch area). Received " + std::to_string(area_ratio) +
".");
1691 std::vector<uint> tile_ObjectIDs;
1693 for (
uint ObjID: ObjIDs) {
1696 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1701 warnings.
addWarning(
"not_a_tile_object",
"ObjectID " + std::to_string(ObjID) +
" is not a tile object. Skipping...");
1702 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1703 warnings.
addWarning(
"tile_object_missing_primitives",
"ObjectID " + std::to_string(ObjID) +
" is missing primitives. Skipping...");
1705 tile_ObjectIDs.push_back(ObjID);
1709 warnings.
report(std::cerr);
1713 for (
uint tile_ObjectID: tile_ObjectIDs) {
1714 Tile *current_object_pointer = getTileObjectPointer_private(tile_ObjectID);
1717 float tile_area = current_object_pointer->
getArea();
1720 float subpatch_dimension = sqrtf(tile_area / area_ratio);
1721 float subpatch_per_x = size.
x / subpatch_dimension;
1722 float subpatch_per_y = size.
y / subpatch_dimension;
1724 float option_1_AR = (tile_area / (size.
x / ceil(subpatch_per_x) * size.
y / floor(subpatch_per_y))) - area_ratio;
1725 float option_2_AR = (tile_area / (size.
x / floor(subpatch_per_x) * size.
y / ceil(subpatch_per_y))) - area_ratio;
1728 if ((
int) area_ratio == 1) {
1730 }
else if (option_1_AR >= option_2_AR) {
1731 new_subdiv =
make_int2(ceil(subpatch_per_x), floor(subpatch_per_y));
1733 new_subdiv =
make_int2(floor(subpatch_per_x), ceil(subpatch_per_y));
1736 regenerateTileObjectSubpatches(tile_ObjectID, new_subdiv);
1744 return addSphere(Ndivs, center, radius, color);
1748 std::vector<uint> UUID;
1750 float dtheta =
PI_F / float(Ndivs);
1751 float dphi = 2.0f *
PI_F / float(Ndivs);
1754 for (
int j = 0; j < Ndivs; j++) {
1763 for (
int j = 0; j < Ndivs; j++) {
1772 for (
int j = 0; j < Ndivs; j++) {
1773 for (
int i = 1; i < Ndivs - 1; i++) {
1788 if (!validateTextureFileExtenstion(texturefile)) {
1789 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1790 }
else if (!doesTextureFileExist(texturefile)) {
1791 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" does not exist.");
1794 std::vector<uint> UUID;
1796 float dtheta =
PI_F / float(Ndivs);
1797 float dphi = 2.0f *
PI_F / float(Ndivs);
1800 for (
int j = 0; j < Ndivs; j++) {
1805 vec3 n0 = v0 - center;
1807 vec3 n1 = v1 - center;
1809 vec3 n2 = v2 - center;
1812 vec2 uv0 =
make_vec2(1.f - atan2f(sin((
float(j) + 0.5f) * dphi), -cos((
float(j) + 0.5f) * dphi)) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
1813 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
1814 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
1816 if (j == Ndivs - 1) {
1820 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1822 UUID.push_back(triangle_uuid);
1829 for (
int j = 0; j < Ndivs; j++) {
1834 vec3 n0 = v0 - center;
1836 vec3 n1 = v1 - center;
1838 vec3 n2 = v2 - center;
1841 vec2 uv0 =
make_vec2(1.f - atan2f(sinf((
float(j) + 0.5f) * dphi), -cosf((
float(j) + 0.5f) * dphi)) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
1842 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
1843 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
1845 if (j == Ndivs - 1) {
1849 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1851 UUID.push_back(triangle_uuid);
1858 for (
int j = 0; j < Ndivs; j++) {
1859 for (
int i = 1; i < Ndivs - 1; i++) {
1865 vec3 n0 = v0 - center;
1867 vec3 n1 = v1 - center;
1869 vec3 n2 = v2 - center;
1871 vec3 n3 = v3 - center;
1874 vec2 uv0 =
make_vec2(1.f - atan2f(n0.
x, -n0.
y) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
1875 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
1876 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
1877 vec2 uv3 =
make_vec2(1.f - atan2f(n3.
x, -n3.
y) / (2.f *
PI_F) - 0.5f, 1.f - n3.
z * 0.5f - 0.5f);
1879 if (j == Ndivs - 1) {
1884 uint triangle_uuid1 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1886 UUID.push_back(triangle_uuid1);
1890 uint triangle_uuid2 =
addTriangle(v0, v2, v3, texturefile, uv0, uv2, uv3);
1892 UUID.push_back(triangle_uuid2);
1905 return addTile(center, size, rotation, subdiv, color);
1910 subsize.
x = size.
x / float(subdiv.
x);
1911 subsize.
y = size.
y / float(subdiv.
y);
1913 std::vector<uint> UUID(subdiv.
x * subdiv.
y);
1916 for (
uint j = 0; j < subdiv.
y; j++) {
1917 for (
uint i = 0; i < subdiv.
x; i++) {
1918 vec3 subcenter =
make_vec3(-0.5f * size.
x + (
float(i) + 0.5f) * subsize.
x, -0.5f * size.
y + (
float(j) + 0.5f) * subsize.
y, 0);
1923 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
elevation,
"x");
1925 if (rotation.
azimuth != 0.f) {
1926 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
azimuth,
"z");
1928 getPrimitivePointer_private(UUID[t])->translate(center);
1938 return addTile(center, size, rotation, subdiv, texturefile,
make_int2(1, 1));
1942 if (!validateTextureFileExtenstion(texturefile)) {
1943 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1944 }
else if (!doesTextureFileExist(texturefile)) {
1945 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" does not exist.");
1946 }
else if (texture_repeat.
x < 1 || texture_repeat.
y < 1) {
1947 helios_runtime_error(
"ERROR (Context::addTile): Number of texture repeats must be greater than 0.");
1951 int2 repeat = texture_repeat;
1952 repeat.
x = std::min(subdiv.
x, repeat.
x);
1953 repeat.
y = std::min(subdiv.
y, repeat.
y);
1954 while (subdiv.
x % repeat.
x != 0) {
1957 while (subdiv.
y % repeat.
y != 0) {
1961 std::vector<uint> UUID;
1964 subsize.
x = size.
x / float(subdiv.
x);
1965 subsize.
y = size.
y / float(subdiv.
y);
1967 std::vector<helios::vec2> uv(4);
1968 int2 sub_per_repeat;
1969 sub_per_repeat.
x = subdiv.
x / repeat.
x;
1970 sub_per_repeat.
y = subdiv.
y / repeat.
y;
1972 uv_sub.
x = 1.f / float(sub_per_repeat.
x);
1973 uv_sub.
y = 1.f / float(sub_per_repeat.
y);
1975 addTexture(texturefile);
1977 const int2 &sz = textures.at(texturefile).getImageResolution();
1978 if (subdiv.
x >= repeat.
x * sz.
x || subdiv.
y >= repeat.
y * sz.
y) {
1979 helios_runtime_error(
"ERROR (Context::addTile): The resolution of the texture image '" + std::string(texturefile) +
"' is lower than the number of tile subdivisions. Increase resolution of the texture image.");
1982 for (
uint j = 0; j < subdiv.
y; j++) {
1983 for (
uint i = 0; i < subdiv.
x; i++) {
1984 vec3 subcenter =
make_vec3(-0.5f * size.
x + (
float(i) + 0.5f) * subsize.
x, -0.5f * size.
y + (
float(j) + 0.5f) * subsize.
y, 0.f);
1986 uint i_local = i % sub_per_repeat.
x;
1987 uint j_local = j % sub_per_repeat.
y;
1988 uv.at(0) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local) * uv_sub.
y);
1989 uv.at(1) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local) * uv_sub.
y);
1990 uv.at(2) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
1991 uv.at(3) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
1993 auto *patch_new = (
new Patch(texturefile, uv, textures, 0, currentUUID));
1995 if (patch_new->getSolidFraction() == 0) {
2000 assert(size.
x > 0.f && size.
y > 0.f);
2001 patch_new->scale(
make_vec3(subsize.
x, subsize.
y, 1));
2003 patch_new->translate(subcenter);
2006 patch_new->rotate(-rotation.
elevation,
"x");
2009 patch_new->rotate(-rotation.
azimuth,
"z");
2012 patch_new->translate(center);
2014 primitives[currentUUID] = patch_new;
2017 patch_new->context_ptr =
this;
2018 patch_new->materialID = 0;
2020 materials[0].reference_count++;
2023 UUID.push_back(currentUUID - 1);
2031 std::vector<RGBcolor> color(nodes.size(),
make_RGBcolor(0.f, 0.75f, 0.f));
2033 return addTube(Ndivs, nodes, radius, color);
2036std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const std::vector<RGBcolor> &color) {
2037 const uint node_count = nodes.size();
2039 if (node_count == 0) {
2041 }
else if (node_count != radius.size()) {
2042 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2043 }
else if (node_count != color.size()) {
2044 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `color' arguments must agree.");
2048 std::vector<float> cfact(radial_subdivisions + 1);
2049 std::vector<float> sfact(radial_subdivisions + 1);
2050 std::vector<std::vector<vec3>> xyz;
2053 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2055 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2056 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2057 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2060 for (
int i = 0; i < node_count; i++) {
2062 if (radius.at(i) < 0) {
2067 vec.
x = nodes[i + 1].x - nodes[i].x;
2068 vec.
y = nodes[i + 1].y - nodes[i].y;
2069 vec.
z = nodes[i + 1].z - nodes[i].z;
2070 }
else if (i == node_count - 1) {
2071 vec.
x = nodes[i].x - nodes[i - 1].x;
2072 vec.
y = nodes[i].y - nodes[i - 1].y;
2073 vec.
z = nodes[i].z - nodes[i - 1].z;
2075 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2076 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2077 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2082 if (fabs(nvec * vec) > 0.95f) {
2083 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2084 if (fabs(nvec * vec) > 0.95f) {
2085 nvec =
vec3(1.0f, 0.0f, 0.0f);
2089 if (fabs(vec.z) > 0.95f) {
2090 nvec =
vec3(1.0f, 0.0f, 0.0f);
2093 convec =
cross(nvec, vec);
2095 nvec =
cross(vec, convec);
2098 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2100 normal.x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2101 normal.y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2102 normal.z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2104 xyz[j][i].x = nodes[i].x + normal.x;
2105 xyz[j][i].y = nodes[i].y + normal.y;
2106 xyz[j][i].z = nodes[i].z + normal.z;
2111 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2114 for (
int i = 0; i < node_count - 1; i++) {
2115 for (
int j = 0; j < radial_subdivisions; j++) {
2117 v1 = xyz[j + 1][i + 1];
2120 UUIDs.at(ii) =
addTriangle(v0, v1, v2, color.at(i));
2124 v2 = xyz[j + 1][i + 1];
2126 UUIDs.at(ii + 1) =
addTriangle(v0, v1, v2, color.at(i));
2135std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile) {
2136 if (!validateTextureFileExtenstion(texturefile)) {
2137 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2138 }
else if (!doesTextureFileExist(texturefile)) {
2139 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" does not exist.");
2142 const uint node_count = nodes.size();
2144 if (node_count == 0) {
2146 }
else if (node_count != radius.size()) {
2147 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2151 std::vector<float> cfact(radial_subdivisions + 1);
2152 std::vector<float> sfact(radial_subdivisions + 1);
2153 std::vector<std::vector<vec3>> xyz, normal;
2154 std::vector<std::vector<vec2>> uv;
2159 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2161 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2162 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2163 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2166 for (
int i = 0; i < node_count; i++) {
2168 if (radius.at(i) < 0) {
2173 vec.
x = nodes[i + 1].x - nodes[i].x;
2174 vec.
y = nodes[i + 1].y - nodes[i].y;
2175 vec.
z = nodes[i + 1].z - nodes[i].z;
2176 }
else if (i == node_count - 1) {
2177 vec.
x = nodes[i].x - nodes[i - 1].x;
2178 vec.
y = nodes[i].y - nodes[i - 1].y;
2179 vec.
z = nodes[i].z - nodes[i - 1].z;
2181 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2182 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2183 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2188 if (fabs(nvec * vec) > 0.95f) {
2189 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2190 if (fabs(nvec * vec) > 0.95f) {
2191 nvec =
vec3(1.0f, 0.0f, 0.0f);
2195 if (fabs(vec.z) > 0.95f) {
2196 nvec =
vec3(1.0f, 0.0f, 0.0f);
2199 convec =
cross(nvec, vec);
2201 nvec =
cross(vec, convec);
2204 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2205 normal[j][i].x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2206 normal[j][i].y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2207 normal[j][i].z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2209 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2210 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2211 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2213 uv[j][i].x = float(i) / float(node_count - 1);
2214 uv[j][i].y = float(j) / float(radial_subdivisions);
2216 normal[j][i] = normal[j][i] / radius[i];
2222 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2225 for (
int i = 0; i < node_count - 1; i++) {
2226 for (
int j = 0; j < radial_subdivisions; j++) {
2228 v1 = xyz[j + 1][i + 1];
2232 uv1 = uv[j + 1][i + 1];
2235 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2237 UUIDs.at(ii) = triangle_uuid;
2245 v2 = xyz[j + 1][i + 1];
2249 uv2 = uv[j + 1][i + 1];
2251 uint triangle_uuid2 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2253 UUIDs.at(ii + 1) = triangle_uuid2;
2256 UUIDs.at(ii + 1) = 0;
2264 UUIDs.erase(std::remove(UUIDs.begin(), UUIDs.end(), 0), UUIDs.end());
2272 return addBox(center, size, subdiv, color,
false);
2276 return addBox(center, size, subdiv, color,
false);
2280 return addBox(center, size, subdiv, texturefile,
false);
2284 std::vector<uint> UUID;
2287 subsize.
x = size.
x / float(subdiv.
x);
2288 subsize.
y = size.
y / float(subdiv.
y);
2289 subsize.
z = size.z / float(subdiv.
z);
2292 std::vector<uint> U;
2294 if (reverse_normals) {
2299 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2301 UUID.insert(UUID.end(), U.begin(), U.end());
2304 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2306 UUID.insert(UUID.end(), U.begin(), U.end());
2311 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2313 UUID.insert(UUID.end(), U.begin(), U.end());
2316 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2318 UUID.insert(UUID.end(), U.begin(), U.end());
2323 subcenter = center +
make_vec3(0, 0, 0.5f * size.z);
2325 UUID.insert(UUID.end(), U.begin(), U.end());
2328 subcenter = center -
make_vec3(0, 0, 0.5f * size.z);
2330 UUID.insert(UUID.end(), U.begin(), U.end());
2336 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2338 UUID.insert(UUID.end(), U.begin(), U.end());
2341 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2343 UUID.insert(UUID.end(), U.begin(), U.end());
2348 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2350 UUID.insert(UUID.end(), U.begin(), U.end());
2353 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2355 UUID.insert(UUID.end(), U.begin(), U.end());
2360 subcenter = center +
make_vec3(0, 0, 0.5f * size.z);
2362 UUID.insert(UUID.end(), U.begin(), U.end());
2365 subcenter = center -
make_vec3(0, 0, 0.5f * size.z);
2367 UUID.insert(UUID.end(), U.begin(), U.end());
2374 if (!validateTextureFileExtenstion(texturefile)) {
2375 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2376 }
else if (!doesTextureFileExist(texturefile)) {
2377 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" does not exist.");
2380 std::vector<uint> UUID;
2383 subsize.
x = size.
x / float(subdiv.
x);
2384 subsize.
y = size.
y / float(subdiv.
y);
2385 subsize.
z = size.z / float(subdiv.
z);
2388 std::vector<uint> U;
2390 if (reverse_normals) {
2395 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2397 UUID.insert(UUID.end(), U.begin(), U.end());
2400 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2402 UUID.insert(UUID.end(), U.begin(), U.end());
2407 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2409 UUID.insert(UUID.end(), U.begin(), U.end());
2412 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2414 UUID.insert(UUID.end(), U.begin(), U.end());
2419 subcenter = center +
make_vec3(0, 0, 0.5f * size.z);
2421 UUID.insert(UUID.end(), U.begin(), U.end());
2424 subcenter = center -
make_vec3(0, 0, 0.5f * size.z);
2426 UUID.insert(UUID.end(), U.begin(), U.end());
2432 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2434 UUID.insert(UUID.end(), U.begin(), U.end());
2437 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2439 UUID.insert(UUID.end(), U.begin(), U.end());
2444 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2446 UUID.insert(UUID.end(), U.begin(), U.end());
2449 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2451 UUID.insert(UUID.end(), U.begin(), U.end());
2456 subcenter = center +
make_vec3(0, 0, 0.5f * size.z);
2458 UUID.insert(UUID.end(), U.begin(), U.end());
2461 subcenter = center -
make_vec3(0, 0, 0.5f * size.z);
2463 UUID.insert(UUID.end(), U.begin(), U.end());
2494 std::vector<uint> UUID(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2496 for (
int r = 0; r < Ndivs.
y; r++) {
2497 for (
int t = 0; t < Ndivs.
x; t++) {
2498 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2499 float theta = dtheta * float(t);
2500 float theta_plus = dtheta * float(t + 1);
2502 float rx = size.
x / float(Ndivs.
y) * float(r);
2503 float ry = size.
y / float(Ndivs.
y) * float(r);
2505 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2506 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2511 UUID.at(i) =
addTriangle(
make_vec3(rx * cosf(theta_plus), ry * sinf(theta_plus), 0),
make_vec3(rx * cosf(theta), ry * sinf(theta), 0),
make_vec3(rx_plus * cosf(theta), ry_plus * sinf(theta), 0), color);
2513 UUID.at(i) =
addTriangle(
make_vec3(rx * cosf(theta_plus), ry * sinf(theta_plus), 0),
make_vec3(rx_plus * cosf(theta), ry_plus * sinf(theta), 0),
make_vec3(rx_plus * cosf(theta_plus), ry_plus * sinf(theta_plus), 0), color);
2515 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
elevation,
"y");
2516 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
azimuth,
"z");
2517 getPrimitivePointer_private(UUID.at(i))->translate(center);
2527 if (!validateTextureFileExtenstion(texturefile)) {
2528 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2529 }
else if (!doesTextureFileExist(texturefile)) {
2530 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" does not exist.");
2533 std::vector<uint> UUID;
2534 UUID.reserve(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2535 for (
int r = 0; r < Ndivs.
y; r++) {
2536 for (
int t = 0; t < Ndivs.
x; t++) {
2537 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2538 float theta = dtheta * float(t);
2539 float theta_plus = dtheta * float(t + 1);
2541 float rx = size.
x / float(Ndivs.
y) * float(r);
2542 float ry = size.
y / float(Ndivs.
y) * float(r);
2543 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2544 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2547 uint triangle_uuid =
addTriangle(
make_vec3(0, 0, 0),
make_vec3(rx_plus * cosf(theta), ry_plus * sinf(theta), 0),
make_vec3(rx_plus * cosf(theta_plus), ry_plus * sinf(theta_plus), 0), texturefile,
make_vec2(0.5, 0.5),
2548 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
2549 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2551 UUID.push_back(triangle_uuid);
2557 uint triangle_uuid1 =
addTriangle(
make_vec3(rx * cosf(theta_plus), ry * sinf(theta_plus), 0),
make_vec3(rx * cosf(theta), ry * sinf(theta), 0),
make_vec3(rx_plus * cosf(theta), ry_plus * sinf(theta), 0), texturefile,
2558 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry / size.
y)),
make_vec2(0.5f * (1.f + cosf(theta) * rx / size.
x), 0.5f * (1.f + sinf(theta) * ry / size.
y)),
2559 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)));
2561 UUID.push_back(triangle_uuid1);
2566 uint triangle_uuid2 =
2567 addTriangle(
make_vec3(rx * cosf(theta_plus), ry * sinf(theta_plus), 0),
make_vec3(rx_plus * cosf(theta), ry_plus * sinf(theta), 0),
make_vec3(rx_plus * cosf(theta_plus), ry_plus * sinf(theta_plus), 0), texturefile,
2568 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry / size.
y)),
make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
2569 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2571 UUID.push_back(triangle_uuid2);
2578 size_t start_idx = UUID.size() - (r == 0 ? 1 : 2);
2579 for (
size_t uuid_idx = start_idx; uuid_idx < UUID.size(); uuid_idx++) {
2580 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
elevation,
"y");
2581 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
azimuth,
"z");
2582 getPrimitivePointer_private(UUID.at(uuid_idx))->translate(center);
2594 return addCone(Ndivs, node0, node1, radius0, radius1, color);
2598 std::vector<helios::vec3> nodes{node0, node1};
2599 std::vector<float> radii{radius0, radius1};
2602 std::vector<float> cfact(Ndivs + 1);
2603 std::vector<float> sfact(Ndivs + 1);
2604 std::vector<std::vector<vec3>> xyz, normal;
2605 xyz.resize(Ndivs + 1);
2606 normal.resize(Ndivs + 1);
2607 for (
uint j = 0; j < Ndivs + 1; j++) {
2608 xyz.at(j).resize(2);
2609 normal.at(j).resize(2);
2611 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2613 for (
int j = 0; j < Ndivs + 1; j++) {
2614 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2615 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2618 for (
int i = 0; i < 2; i++) {
2621 vec.
x = nodes[i + 1].x - nodes[i].x;
2622 vec.
y = nodes[i + 1].y - nodes[i].y;
2623 vec.
z = nodes[i + 1].z - nodes[i].z;
2624 }
else if (i == 1) {
2625 vec.
x = nodes[i].x - nodes[i - 1].x;
2626 vec.
y = nodes[i].y - nodes[i - 1].y;
2627 vec.
z = nodes[i].z - nodes[i - 1].z;
2631 convec =
cross(nvec, vec);
2633 convec.
x = convec.
x / norm;
2634 convec.
y = convec.
y / norm;
2635 convec.
z = convec.
z / norm;
2636 nvec =
cross(vec, convec);
2638 nvec.
x = nvec.
x / norm;
2639 nvec.
y = nvec.
y / norm;
2640 nvec.
z = nvec.
z / norm;
2643 for (
int j = 0; j < Ndivs + 1; j++) {
2644 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2645 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2646 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2648 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2649 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2650 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2652 normal[j][i] = normal[j][i] / radii[i];
2657 std::vector<uint> UUID;
2659 for (
int i = 0; i < 2 - 1; i++) {
2660 for (
int j = 0; j < Ndivs; j++) {
2662 v1 = xyz[j + 1][i + 1];
2669 v2 = xyz[j + 1][i + 1];
2679 if (!validateTextureFileExtenstion(texturefile)) {
2680 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2681 }
else if (!doesTextureFileExist(texturefile)) {
2682 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" does not exist.");
2685 std::vector<helios::vec3> nodes{node0, node1};
2686 std::vector<float> radii{radius0, radius1};
2689 std::vector<float> cfact(Ndivs + 1);
2690 std::vector<float> sfact(Ndivs + 1);
2691 std::vector<std::vector<vec3>> xyz, normal;
2692 std::vector<std::vector<vec2>> uv;
2693 xyz.resize(Ndivs + 1);
2694 normal.resize(Ndivs + 1);
2695 uv.resize(Ndivs + 1);
2696 for (
uint j = 0; j < Ndivs + 1; j++) {
2697 xyz.at(j).resize(2);
2698 normal.at(j).resize(2);
2701 vec3 nvec(0.f, 1.f, 0.f);
2703 for (
int j = 0; j < Ndivs + 1; j++) {
2704 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2705 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2708 for (
int i = 0; i < 2; i++) {
2711 vec.
x = nodes[i + 1].x - nodes[i].x;
2712 vec.
y = nodes[i + 1].y - nodes[i].y;
2713 vec.
z = nodes[i + 1].z - nodes[i].z;
2714 }
else if (i == 1) {
2715 vec.
x = nodes[i].x - nodes[i - 1].x;
2716 vec.
y = nodes[i].y - nodes[i - 1].y;
2717 vec.
z = nodes[i].z - nodes[i - 1].z;
2721 convec =
cross(nvec, vec);
2723 convec.
x = convec.
x / norm;
2724 convec.
y = convec.
y / norm;
2725 convec.
z = convec.
z / norm;
2726 nvec =
cross(vec, convec);
2728 nvec.
x = nvec.
x / norm;
2729 nvec.
y = nvec.
y / norm;
2730 nvec.
z = nvec.
z / norm;
2732 for (
int j = 0; j < Ndivs + 1; j++) {
2733 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2734 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2735 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2737 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2738 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2739 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2741 uv[j][i].x = float(i) / float(2 - 1);
2742 uv[j][i].y = float(j) / float(Ndivs);
2744 normal[j][i] = normal[j][i] / radii[i];
2750 std::vector<uint> UUID;
2752 for (
int i = 0; i < 2 - 1; i++) {
2753 for (
int j = 0; j < Ndivs; j++) {
2755 v1 = xyz[j + 1][i + 1];
2759 uv1 = uv[j + 1][i + 1];
2762 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2763 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2765 UUID.push_back(triangle_uuid);
2773 v2 = xyz[j + 1][i + 1];
2777 uv2 = uv[j + 1][i + 1];
2779 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2780 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2782 UUID.push_back(triangle_uuid);
2798 std::map<uint, float> pcolor_data;
2801 float data_min_new = 9999999;
2802 float data_max_new = -9999999;
2803 for (
uint UUID: UUIDs) {
2805 warnings.
addWarning(
"primitive_does_not_exist",
"Primitive for UUID " + std::to_string(UUID) +
" does not exist. Skipping this primitive.");
2813 warnings.
addWarning(
"unsupported_data_type",
"Only primitive data types of int, uint, float, and double are supported for this function. Skipping this primitive.");
2824 dataf = float(data);
2828 dataf = float(data);
2832 dataf = float(data);
2836 if (data_min == 9999999 && data_max == -9999999) {
2837 if (dataf < data_min_new) {
2838 data_min_new = dataf;
2840 if (dataf > data_max_new) {
2841 data_max_new = dataf;
2845 pcolor_data[UUID] = dataf;
2848 if (data_min == 9999999 && data_max == -9999999) {
2849 data_min = data_min_new;
2850 data_max = data_max_new;
2855 std::map<std::string, std::vector<std::string>> cmap_texture_filenames;
2857 for (
auto &[UUID, pdata]: pcolor_data) {
2860 int cmap_ind = std::round((pdata - data_min) / (data_max - data_min) *
float(Ncolors - 1));
2864 }
else if (cmap_ind >= Ncolors) {
2865 cmap_ind = Ncolors - 1;
2882 warnings.
report(std::cerr);
2886 if (Ncolors > 9999) {
2887 std::cerr <<
"WARNING (Context::generateColormap): Truncating number of color map textures to maximum value of 9999." << std::endl;
2890 if (ctable.size() != cfrac.size()) {
2891 helios_runtime_error(
"ERROR (Context::generateColormap): The length of arguments 'ctable' and 'cfrac' must match.");
2893 if (ctable.empty()) {
2894 helios_runtime_error(
"ERROR (Context::generateColormap): 'ctable' and 'cfrac' arguments contain empty vectors.");
2897 std::vector<RGBcolor> color_table(Ncolors);
2899 for (
int i = 0; i < Ncolors; i++) {
2900 float frac = float(i) / float(Ncolors - 1) * cfrac.back();
2903 for (j = 0; j < cfrac.size() - 1; j++) {
2904 if (frac >= cfrac.at(j) && frac <= cfrac.at(j + 1)) {
2909 float cminus = std::fmaxf(0.f, cfrac.at(j));
2910 float cplus = std::fminf(1.f, cfrac.at(j + 1));
2912 float jfrac = (frac - cminus) / (cplus - cminus);
2915 color.
r = ctable.at(j).r + jfrac * (ctable.at(j + 1).r - ctable.at(j).r);
2916 color.
g = ctable.at(j).g + jfrac * (ctable.at(j + 1).g - ctable.at(j).g);
2917 color.
b = ctable.at(j).b + jfrac * (ctable.at(j + 1).b - ctable.at(j).b);
2919 color_table.at(i) = color;
2926 std::vector<RGBcolor> ctable_c;
2927 std::vector<float> clocs_c;
2929 if (colormap ==
"hot") {
2938 clocs_c.at(0) = 0.f;
2939 clocs_c.at(1) = 0.25f;
2940 clocs_c.at(2) = 0.5f;
2941 clocs_c.at(3) = 0.75f;
2942 clocs_c.at(4) = 1.f;
2943 }
else if (colormap ==
"cool") {
2945 ctable_c.at(0) = RGB::cyan;
2946 ctable_c.at(1) = RGB::magenta;
2949 clocs_c.at(0) = 0.f;
2950 clocs_c.at(1) = 1.f;
2951 }
else if (colormap ==
"lava") {
2960 clocs_c.at(0) = 0.f;
2961 clocs_c.at(1) = 0.4f;
2962 clocs_c.at(2) = 0.5f;
2963 clocs_c.at(3) = 0.6f;
2964 clocs_c.at(4) = 1.f;
2965 }
else if (colormap ==
"rainbow") {
2967 ctable_c.at(0) = RGB::navy;
2968 ctable_c.at(1) = RGB::cyan;
2969 ctable_c.at(2) = RGB::yellow;
2973 clocs_c.at(0) = 0.f;
2974 clocs_c.at(1) = 0.3f;
2975 clocs_c.at(2) = 0.7f;
2976 clocs_c.at(3) = 1.f;
2977 }
else if (colormap ==
"parula") {
2979 ctable_c.at(0) = RGB::navy;
2981 ctable_c.at(2) = RGB::goldenrod;
2982 ctable_c.at(3) = RGB::yellow;
2985 clocs_c.at(0) = 0.f;
2986 clocs_c.at(1) = 0.4f;
2987 clocs_c.at(2) = 0.7f;
2988 clocs_c.at(3) = 1.f;
2989 }
else if (colormap ==
"gray") {
2991 ctable_c.at(0) = RGB::black;
2992 ctable_c.at(1) = RGB::white;
2995 clocs_c.at(0) = 0.f;
2996 clocs_c.at(1) = 1.f;
2997 }
else if (colormap ==
"green") {
2999 ctable_c.at(0) = RGB::black;
3000 ctable_c.at(1) = RGB::green;
3003 clocs_c.at(0) = 0.f;
3004 clocs_c.at(1) = 1.f;
3006 helios_runtime_error(
"ERROR (Context::generateColormapTextures): Unknown colormap " + colormap +
".");
3013 uint Ncolors = colormap_data.size();
3016 std::ifstream tfile(texturefile);
3018 helios_runtime_error(
"ERROR (Context::generateTexturesFromColormap): Texture file " + texturefile +
" does not exist, or you do not have permission to read it.");
3028 std::vector<RGBcolor> color_table(Ncolors);
3030 std::vector<std::string> texture_filenames(Ncolors);
3032 if (file_ext ==
"png" || file_ext ==
"PNG") {
3033 std::vector<RGBAcolor> pixel_data;
3035 readPNG(texturefile, width, height, pixel_data);
3037 for (
int i = 0; i < Ncolors; i++) {
3038 std::ostringstream filename;
3039 filename <<
"lib/images/colormap_" << file_base <<
"_" << std::setw(4) << std::setfill(
'0') << std::to_string(i) <<
".png";
3041 texture_filenames.at(i) = filename.str();
3043 RGBcolor color = colormap_data.at(i);
3045 for (
int row = 0; row < height; row++) {
3046 for (
int col = 0; col < width; col++) {
3047 pixel_data.at(row * width + col) =
make_RGBAcolor(color, pixel_data.at(row * width + col).a);
3051 writePNG(filename.str(), width, height, pixel_data);
3055 return texture_filenames;
3058void Context::out_of_memory_handler() {
3059 helios_runtime_error(
"ERROR: Out of host memory. The program has run out of memory and cannot continue.");
3062void Context::install_out_of_memory_handler() {
3063 std::set_new_handler(out_of_memory_handler);
3067 for (
auto &[UUID, primitive]: primitives) {
3068 delete getPrimitivePointer_private(UUID);
3071 for (
auto &[UUID,
object]: objects) {
3072 delete getObjectPointer_private(UUID);
3079 helios_runtime_error(
"ERROR (Context::getPrimitiveType): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3082 return getPrimitivePointer_private(UUID)->getType();
3088 helios_runtime_error(
"ERROR (Context::setPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3092 uint current_objID = getPrimitivePointer_private(UUID)->getParentObjectID();
3093 getPrimitivePointer_private(UUID)->setParentObjectID(objID);
3095 if (current_objID != 0u && current_objID != objID) {
3097 objects.at(current_objID)->deleteChildPrimitive(UUID);
3099 if (getObjectPointer_private(current_objID)->getPrimitiveUUIDs().empty()) {
3102 objects.erase(current_objID);
3109 for (
uint UUID: UUIDs) {
3117 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3120 return getPrimitivePointer_private(UUID)->getParentObjectID();
3124 std::vector<uint> objIDs(UUIDs.size());
3125 for (
uint i = 0; i < UUIDs.size(); i++) {
3128 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUIDs[i]) +
" does not exist in the Context.");
3131 objIDs[i] = getPrimitivePointer_private(UUIDs[i])->getParentObjectID();
3143 std::vector<uint> primitiveObjIDs;
3144 if (UUIDs.empty()) {
3145 return primitiveObjIDs;
3149 primitiveObjIDs.resize(UUIDs.size());
3150 for (
uint i = 0; i < UUIDs.size(); i++) {
3153 helios_runtime_error(
"ERROR (Context::getUniquePrimitiveParentObjectIDs): Primitive with UUID of " + std::to_string(UUIDs.at(i)) +
" does not exist in the Context.");
3156 primitiveObjIDs.at(i) = getPrimitivePointer_private(UUIDs.at(i))->getParentObjectID();
3160 std::sort(primitiveObjIDs.begin(), primitiveObjIDs.end());
3163 auto it = unique(primitiveObjIDs.begin(), primitiveObjIDs.end());
3164 primitiveObjIDs.resize(distance(primitiveObjIDs.begin(), it));
3167 if (include_ObjID_zero ==
false & primitiveObjIDs.front() ==
uint(0)) {
3168 primitiveObjIDs.erase(primitiveObjIDs.begin());
3171 return primitiveObjIDs;
3177 helios_runtime_error(
"ERROR (Context::getPrimitiveArea): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3180 return getPrimitivePointer_private(UUID)->getArea();
3184 const std::vector UUIDs = {UUID};
3190 for (
uint UUID: UUIDs) {
3192 helios_runtime_error(
"ERROR (Context::getPrimitiveBoundingBox): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3198 min_corner = vertices.front();
3199 max_corner = min_corner;
3202 for (
const vec3 &vert: vertices) {
3203 if (vert.x < min_corner.
x) {
3204 min_corner.
x = vert.x;
3206 if (vert.y < min_corner.
y) {
3207 min_corner.
y = vert.y;
3209 if (vert.z < min_corner.
z) {
3210 min_corner.
z = vert.z;
3212 if (vert.x > max_corner.
x) {
3213 max_corner.
x = vert.x;
3215 if (vert.y > max_corner.
y) {
3216 max_corner.
y = vert.y;
3218 if (vert.z > max_corner.
z) {
3219 max_corner.
z = vert.z;
3228 return getPrimitivePointer_private(UUID)->getNormal();
3232 getPrimitivePointer_private(UUID)->getTransformationMatrix(T);
3236 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3240 for (
uint UUID: UUIDs) {
3241 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3246 return getPrimitivePointer_private(UUID)->getVertices();
3251 return getPrimitivePointer_private(UUID)->getColor();
3255 return getPrimitivePointer_private(UUID)->getColorRGB();
3259 return getPrimitivePointer_private(UUID)->getColorRGBA();
3263 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3264 getPrimitivePointer_private(UUID)->setColor(color);
3268 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3269 for (
uint UUID: UUIDs) {
3270 getPrimitivePointer_private(UUID)->setColor(color);
3275 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3276 getPrimitivePointer_private(UUID)->setColor(color);
3280 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3281 for (
uint UUID: UUIDs) {
3282 getPrimitivePointer_private(UUID)->setColor(color);
3287 return getPrimitivePointer_private(UUID)->getTextureFile();
3291 api_warnings.
addWarning(
"setPrimitiveTextureFile_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3292 getPrimitivePointer_private(UUID)->setTextureFile(texturefile.c_str());
3296 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3297 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3298 return textures.at(texturefile).getImageResolution();
3304 return getPrimitivePointer_private(UUID)->getTextureUV();
3308 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3309 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3310 return textures.at(texturefile).hasTransparencyChannel();
3317 const std::vector<std::vector<bool>> *data = textures.at(getPrimitivePointer_private(UUID)->getTextureFile()).getTransparencyData();
3321 helios_runtime_error(
"ERROR (Context::getPrimitiveTransparencyData): Texture transparency data does not exist for primitive " + std::to_string(UUID) +
".");
3326 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3327 getPrimitivePointer_private(UUID)->overrideTextureColor();
3331 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3332 for (
uint UUID: UUIDs) {
3333 getPrimitivePointer_private(UUID)->overrideTextureColor();
3338 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3339 getPrimitivePointer_private(UUID)->useTextureColor();
3343 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3344 for (
uint UUID: UUIDs) {
3345 getPrimitivePointer_private(UUID)->useTextureColor();
3350 return getPrimitivePointer_private(UUID)->isTextureColorOverridden();
3354 return getPrimitivePointer_private(UUID)->getSolidFraction();
3358 std::cout <<
"-------------------------------------------" << std::endl;
3359 std::cout <<
"Info for UUID " << UUID << std::endl;
3360 std::cout <<
"-------------------------------------------" << std::endl;
3365 stype =
"PRIMITIVE_TYPE_PATCH";
3366 }
else if (type == 1) {
3367 stype =
"PRIMITIVE_TYPE_TRIANGLE";
3368 }
else if (type == 2) {
3369 stype =
"PRIMITIVE_TYPE_VOXEL";
3372 std::cout <<
"Type: " << stype << std::endl;
3378 std::cout <<
"Patch Center: " <<
getPatchCenter(UUID) << std::endl;
3379 std::cout <<
"Patch Size: " <<
getPatchSize(UUID) << std::endl;
3381 std::cout <<
"Voxel Center: " <<
getVoxelCenter(UUID) << std::endl;
3382 std::cout <<
"Voxel Size: " <<
getVoxelSize(UUID) << std::endl;
3386 std::cout <<
"Vertices: " << std::endl;
3387 for (
uint i = 0; i < primitive_vertices.size(); i++) {
3388 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
3393 std::cout <<
"Transform: " << std::endl;
3394 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
3395 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
3396 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
3397 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
3402 std::cout <<
"Texture UV: " << std::endl;
3404 for (
uint i = 0; i < uv.size(); i++) {
3405 std::cout <<
" " << uv.at(i) << std::endl;
3413 std::cout <<
"Primitive Data: " << std::endl;
3416 for (
uint i = 0; i < pd.size(); i++) {
3422 dstype =
"HELIOS_TYPE_INT";
3424 dstype =
"HELIOS_TYPE_UINT";
3426 dstype =
"HELIOS_TYPE_FLOAT";
3428 dstype =
"HELIOS_TYPE_DOUBLE";
3430 dstype =
"HELIOS_TYPE_VEC2";
3432 dstype =
"HELIOS_TYPE_VEC3";
3434 dstype =
"HELIOS_TYPE_VEC4";
3436 dstype =
"HELIOS_TYPE_INT2";
3438 dstype =
"HELIOS_TYPE_INT3";
3440 dstype =
"HELIOS_TYPE_INT4";
3442 dstype =
"HELIOS_TYPE_STRING";
3448 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
3452 std::vector<int> pdata;
3454 for (
uint j = 0; j < dsize; j++) {
3456 std::cout <<
" " << pdata.at(j) << std::endl;
3458 std::cout <<
" ..." << std::endl;
3459 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3460 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3465 std::vector<uint> pdata;
3467 for (
uint j = 0; j < dsize; j++) {
3469 std::cout <<
" " << pdata.at(j) << std::endl;
3471 std::cout <<
" ..." << std::endl;
3472 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3473 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3478 std::vector<float> pdata;
3480 for (
uint j = 0; j < dsize; j++) {
3482 std::cout <<
" " << pdata.at(j) << std::endl;
3484 std::cout <<
" ..." << std::endl;
3485 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3486 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3491 std::vector<double> pdata;
3493 for (
uint j = 0; j < dsize; j++) {
3495 std::cout <<
" " << pdata.at(j) << std::endl;
3497 std::cout <<
" ..." << std::endl;
3498 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3499 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3504 std::vector<vec2> pdata;
3506 for (
uint j = 0; j < dsize; j++) {
3508 std::cout <<
" " << pdata.at(j) << std::endl;
3510 std::cout <<
" ..." << std::endl;
3511 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3512 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3517 std::vector<vec3> pdata;
3519 for (
uint j = 0; j < dsize; j++) {
3521 std::cout <<
" " << pdata.at(j) << std::endl;
3523 std::cout <<
" ..." << std::endl;
3524 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3525 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3530 std::vector<vec4> pdata;
3532 for (
uint j = 0; j < dsize; j++) {
3534 std::cout <<
" " << pdata.at(j) << std::endl;
3536 std::cout <<
" ..." << std::endl;
3537 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3538 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3543 std::vector<int2> pdata;
3545 for (
uint j = 0; j < dsize; j++) {
3547 std::cout <<
" " << pdata.at(j) << std::endl;
3549 std::cout <<
" ..." << std::endl;
3550 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3551 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3556 std::vector<int3> pdata;
3558 for (
uint j = 0; j < dsize; j++) {
3560 std::cout <<
" " << pdata.at(j) << std::endl;
3562 std::cout <<
" ..." << std::endl;
3563 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3564 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3569 std::vector<int4> pdata;
3571 for (
uint j = 0; j < dsize; j++) {
3573 std::cout <<
" " << pdata.at(j) << std::endl;
3575 std::cout <<
" ..." << std::endl;
3576 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3577 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3582 std::vector<std::string> pdata;
3584 for (
uint j = 0; j < dsize; j++) {
3586 std::cout <<
" " << pdata.at(j) << std::endl;
3588 std::cout <<
" ..." << std::endl;
3589 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3590 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3598 std::cout <<
"-------------------------------------------" << std::endl;
3604 auto it = material_label_to_id.find(material_label);
3605 if (it == material_label_to_id.end()) {
3606 helios_runtime_error(
"ERROR (Context::getMaterialIDFromLabel): Material with label '" + material_label +
"' does not exist.");
3612 if (material_label.empty()) {
3617 if (material_label.substr(0, 2) ==
"__" && material_label != DEFAULT_MATERIAL_LABEL) {
3618 helios_runtime_error(
"ERROR (Context::addMaterial): Material labels starting with '__' are reserved for internal use.");
3622 if (material_label_to_id.find(material_label) != material_label_to_id.end()) {
3623 std::cerr <<
"WARNING (Context::addMaterial): Material with label '" << material_label <<
"' already exists. Overwriting." << std::endl;
3625 uint oldID = material_label_to_id[material_label];
3626 materials.erase(oldID);
3630 uint newID = currentMaterialID++;
3632 materials[newID] = newMaterial;
3633 material_label_to_id[material_label] = newID;
3636uint Context::addMaterial_internal(
const std::string &label,
const RGBAcolor &color,
const std::string &texture) {
3638 if (label.empty()) {
3639 helios_runtime_error(
"ERROR (Context::addMaterial_internal): Material label cannot be empty.");
3643 if (material_label_to_id.find(label) != material_label_to_id.end()) {
3644 uint oldID = material_label_to_id[label];
3645 materials.erase(oldID);
3649 uint newID = currentMaterialID++;
3650 Material newMaterial(newID, label, color, texture,
false);
3651 materials[newID] = newMaterial;
3652 material_label_to_id[label] = newID;
3656std::string Context::generateMaterialLabel(
const RGBAcolor &color,
const std::string &texture,
bool texture_override)
const {
3659 hash ^= std::hash<float>{}(color.
r) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3660 hash ^= std::hash<float>{}(color.
g) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3661 hash ^= std::hash<float>{}(color.
b) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3662 hash ^= std::hash<float>{}(color.
a) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3663 hash ^= std::hash<std::string>{}(texture) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3664 hash ^= std::hash<bool>{}(texture_override) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3665 return "__auto_" + std::to_string(hash);
3668bool Context::isMaterialShared(
uint materialID)
const {
3669 if (materials.find(materialID) == materials.end()) {
3673 return materials.at(materialID).reference_count > 1;
3676uint Context::copyMaterialForPrimitive(
uint primitiveUUID) {
3677 Primitive *prim = getPrimitivePointer_private(primitiveUUID);
3678 uint oldMaterialID = prim->materialID;
3679 const Material &oldMaterial = materials.at(oldMaterialID);
3682 std::string newLabel =
"__copy_" + std::to_string(currentMaterialID) +
"_" + std::to_string(primitiveUUID);
3689 materials[newMaterialID].twosided_flag = oldMaterial.
twosided_flag;
3707 materials[oldMaterialID].reference_count--;
3708 materials[newMaterialID].reference_count = 1;
3711 prim->materialID = newMaterialID;
3713 return newMaterialID;
3717 if (material_label_to_id.find(old_label) == material_label_to_id.end()) {
3718 helios_runtime_error(
"ERROR (Context::renameMaterial): Material with label '" + old_label +
"' does not exist.");
3720 if (new_label.empty()) {
3723 if (new_label.substr(0, 2) ==
"__") {
3724 helios_runtime_error(
"ERROR (Context::renameMaterial): Material labels starting with '__' are reserved for internal use.");
3726 if (material_label_to_id.find(new_label) != material_label_to_id.end()) {
3727 helios_runtime_error(
"ERROR (Context::renameMaterial): Material with label '" + new_label +
"' already exists.");
3730 uint materialID = material_label_to_id.at(old_label);
3731 materials.at(materialID).label = new_label;
3734 if (old_label.substr(0, 7) !=
"__auto_") {
3735 material_label_to_id.erase(old_label);
3737 material_label_to_id[new_label] = materialID;
3741 return material_label_to_id.find(material_label) != material_label_to_id.end();
3745 std::vector<std::string> labels;
3746 labels.reserve(material_label_to_id.size());
3747 for (
const auto &pair: material_label_to_id) {
3749 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
3750 labels.push_back(pair.first);
3758 return materials.at(matID).color;
3763 return materials.at(matID).texture_file;
3768 return materials.at(matID).texture_color_overridden;
3773 materials[matID].color = color;
3779 if (!texture_file.empty()) {
3780 addTexture(texture_file.c_str());
3782 materials[matID].texture_file = texture_file;
3787 materials[matID].texture_color_overridden =
override;
3792 return materials.at(matID).twosided_flag;
3797 materials[matID].twosided_flag = twosided_flag;
3802 bool has_user_material = (mat_label.substr(0, 7) !=
"__auto_" && mat_label != DEFAULT_MATERIAL_LABEL);
3804 if (has_user_material) {
3814 return default_value;
3819 Primitive *prim = getPrimitivePointer_private(UUID);
3820 uint oldMaterialID = prim->materialID;
3822 materials[oldMaterialID].reference_count--;
3823 materials[materialID].reference_count++;
3824 prim->materialID = materialID;
3829 for (
uint UUID: UUIDs) {
3830 Primitive *prim = getPrimitivePointer_private(UUID);
3831 uint oldMaterialID = prim->materialID;
3833 materials[oldMaterialID].reference_count--;
3834 materials[materialID].reference_count++;
3835 prim->materialID = materialID;
3845 for (
uint ObjID: ObjIDs) {
3851 Primitive *prim = getPrimitivePointer_private(UUID);
3852 uint materialID = prim->materialID;
3854 if (materials.find(materialID) != materials.end()) {
3855 return materials.at(materialID).label;
3857 return DEFAULT_MATERIAL_LABEL;
3862 std::vector<uint> result;
3863 for (
const auto &pair: primitives) {
3864 if (pair.second->materialID == materialID) {
3865 result.push_back(pair.first);
3872 if (material_label == DEFAULT_MATERIAL_LABEL) {
3876 auto it = material_label_to_id.find(material_label);
3877 if (it == material_label_to_id.end()) {
3878 helios_runtime_error(
"ERROR (Context::deleteMaterial): Material with label '" + material_label +
"' does not exist.");
3881 uint materialID = it->second;
3885 if (!users.empty()) {
3886 std::cerr <<
"WARNING (Context::deleteMaterial): Material '" << material_label <<
"' is in use by " << users.size() <<
" primitives. They will be reassigned to the default material." << std::endl;
3888 for (
uint UUID: users) {
3889 Primitive *prim = getPrimitivePointer_private(UUID);
3891 materials[materialID].reference_count--;
3892 prim->materialID = 0;
3893 materials[0].reference_count++;
3898 materials.erase(materialID);
3899 material_label_to_id.erase(material_label);
3904 return materials.at(matID).doesMaterialDataExist(data_label);
3909 return materials.at(matID).getMaterialDataType(data_label);
3914 materials[matID].clearMaterialData(data_label);
3918 Primitive *prim = getPrimitivePointer_private(UUID);
3919 return prim->materialID;
3923 if (materials.find(materialID) == materials.end()) {
3924 helios_runtime_error(
"ERROR (Context::getMaterial): Material ID " + std::to_string(materialID) +
" does not exist.");
3926 return materials.at(materialID);
3932 for (
const auto &pair: material_label_to_id) {
3934 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
3942 std::cout <<
"-------------------------------------------" << std::endl;
3943 std::cout <<
"Info for ObjID " << ObjID << std::endl;
3944 std::cout <<
"-------------------------------------------" << std::endl;
3949 ostype =
"OBJECT_TYPE_TILE";
3950 }
else if (otype == 1) {
3951 ostype =
"OBJECT_TYPE_SPHERE";
3952 }
else if (otype == 2) {
3953 ostype =
"OBJECT_TYPE_TUBE";
3954 }
else if (otype == 3) {
3955 ostype =
"OBJECT_TYPE_BOX";
3956 }
else if (otype == 4) {
3957 ostype =
"OBJECT_TYPE_DISK";
3958 }
else if (otype == 5) {
3959 ostype =
"OBJECT_TYPE_POLYMESH";
3960 }
else if (otype == 6) {
3961 ostype =
"OBJECT_TYPE_CONE";
3964 std::cout <<
"Type: " << ostype << std::endl;
3965 std::cout <<
"Object Bounding Box Center: " <<
getObjectCenter(ObjID) << std::endl;
3966 std::cout <<
"One-sided Surface Area: " <<
getObjectArea(ObjID) << std::endl;
3971 std::cout <<
"Object Primitives Complete" << std::endl;
3973 std::cout <<
"Object Primitives Incomplete" << std::endl;
3976 std::cout <<
"Primitive UUIDs: " << std::endl;
3978 for (
uint i = 0; i < primitive_UUIDs.size(); i++) {
3983 pstype =
"PRIMITIVE_TYPE_PATCH";
3984 }
else if (ptype == 1) {
3985 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
3987 std::cout <<
" " << primitive_UUIDs.at(i) <<
" (" << pstype <<
")" << std::endl;
3989 std::cout <<
" ..." << std::endl;
3993 pstype =
"PRIMITIVE_TYPE_PATCH";
3994 }
else if (ptype == 1) {
3995 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
3997 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 2) <<
" (" << pstype <<
")" << std::endl;
4000 pstype =
"PRIMITIVE_TYPE_PATCH";
4001 }
else if (ptype == 1) {
4002 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4004 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 1) <<
" (" << pstype <<
")" << std::endl;
4015 std::cout <<
"Tile Texture UV: " << std::endl;
4017 for (
uint i = 0; i < uv.size(); i++) {
4018 std::cout <<
" " << uv.at(i) << std::endl;
4021 std::cout <<
"Tile Vertices: " << std::endl;
4023 for (
uint i = 0; i < primitive_vertices.size(); i++) {
4024 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
4032 std::cout <<
"Tube Nodes: " << std::endl;
4034 for (
uint i = 0; i < nodes.size(); i++) {
4036 std::cout <<
" " << nodes.at(i) << std::endl;
4038 std::cout <<
" ..." << std::endl;
4039 std::cout <<
" " << nodes.at(nodes.size() - 2) << std::endl;
4040 std::cout <<
" " << nodes.at(nodes.size() - 1) << std::endl;
4044 std::cout <<
"Tube Node Radii: " << std::endl;
4046 for (
uint i = 0; i < noderadii.size(); i++) {
4048 std::cout <<
" " << noderadii.at(i) << std::endl;
4050 std::cout <<
" ..." << std::endl;
4051 std::cout <<
" " << noderadii.at(noderadii.size() - 2) << std::endl;
4052 std::cout <<
" " << noderadii.at(noderadii.size() - 1) << std::endl;
4056 std::cout <<
"Tube Node Colors: " << std::endl;
4058 for (
uint i = 0; i < nodecolors.size(); i++) {
4060 std::cout <<
" " << nodecolors.at(i) << std::endl;
4062 std::cout <<
" ..." << std::endl;
4063 std::cout <<
" " << nodecolors.at(nodecolors.size() - 2) << std::endl;
4064 std::cout <<
" " << nodecolors.at(nodecolors.size() - 1) << std::endl;
4083 std::cout <<
"Cone Nodes: " << std::endl;
4085 for (
uint i = 0; i < nodes.size(); i++) {
4086 std::cout <<
" " << nodes.at(i) << std::endl;
4088 std::cout <<
"Cone Node Radii: " << std::endl;
4090 for (
uint i = 0; i < noderadii.size(); i++) {
4091 std::cout <<
" " << noderadii.at(i) << std::endl;
4098 std::cout <<
"Transform: " << std::endl;
4099 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
4100 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
4101 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
4102 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
4106 std::cout <<
"Object Data: " << std::endl;
4109 for (
uint i = 0; i < pd.size(); i++) {
4115 dstype =
"HELIOS_TYPE_INT";
4117 dstype =
"HELIOS_TYPE_UINT";
4119 dstype =
"HELIOS_TYPE_FLOAT";
4121 dstype =
"HELIOS_TYPE_DOUBLE";
4123 dstype =
"HELIOS_TYPE_VEC2";
4125 dstype =
"HELIOS_TYPE_VEC3";
4127 dstype =
"HELIOS_TYPE_VEC4";
4129 dstype =
"HELIOS_TYPE_INT2";
4131 dstype =
"HELIOS_TYPE_INT3";
4133 dstype =
"HELIOS_TYPE_INT4";
4135 dstype =
"HELIOS_TYPE_STRING";
4141 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
4145 std::vector<int> pdata;
4147 for (
uint j = 0; j < dsize; j++) {
4149 std::cout <<
" " << pdata.at(j) << std::endl;
4151 std::cout <<
" ..." << std::endl;
4152 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4153 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4158 std::vector<uint> pdata;
4160 for (
uint j = 0; j < dsize; j++) {
4162 std::cout <<
" " << pdata.at(j) << std::endl;
4164 std::cout <<
" ..." << std::endl;
4165 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4166 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4171 std::vector<float> pdata;
4173 for (
uint j = 0; j < dsize; j++) {
4175 std::cout <<
" " << pdata.at(j) << std::endl;
4177 std::cout <<
" ..." << std::endl;
4178 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4179 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4184 std::vector<double> pdata;
4186 for (
uint j = 0; j < dsize; j++) {
4188 std::cout <<
" " << pdata.at(j) << std::endl;
4190 std::cout <<
" ..." << std::endl;
4191 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4192 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4197 std::vector<vec2> pdata;
4199 for (
uint j = 0; j < dsize; j++) {
4201 std::cout <<
" " << pdata.at(j) << std::endl;
4203 std::cout <<
" ..." << std::endl;
4204 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4205 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4210 std::vector<vec3> pdata;
4212 for (
uint j = 0; j < dsize; j++) {
4214 std::cout <<
" " << pdata.at(j) << std::endl;
4216 std::cout <<
" ..." << std::endl;
4217 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4218 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4223 std::vector<vec4> pdata;
4225 for (
uint j = 0; j < dsize; j++) {
4227 std::cout <<
" " << pdata.at(j) << std::endl;
4229 std::cout <<
" ..." << std::endl;
4230 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4231 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4236 std::vector<int2> pdata;
4238 for (
uint j = 0; j < dsize; j++) {
4240 std::cout <<
" " << pdata.at(j) << std::endl;
4242 std::cout <<
" ..." << std::endl;
4243 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4244 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4249 std::vector<int3> pdata;
4251 for (
uint j = 0; j < dsize; j++) {
4253 std::cout <<
" " << pdata.at(j) << std::endl;
4255 std::cout <<
" ..." << std::endl;
4256 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4257 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4262 std::vector<int4> pdata;
4264 for (
uint j = 0; j < dsize; j++) {
4266 std::cout <<
" " << pdata.at(j) << std::endl;
4268 std::cout <<
" ..." << std::endl;
4273 std::vector<std::string> pdata;
4275 for (
uint j = 0; j < dsize; j++) {
4277 std::cout <<
" " << pdata.at(j) << std::endl;
4279 std::cout <<
" ..." << std::endl;
4287 std::cout <<
"-------------------------------------------" << std::endl;
4292 if (objects.find(ObjID) == objects.end()) {
4293 helios_runtime_error(
"ERROR (Context::getObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4296 return objects.at(ObjID);
4302 helios_runtime_error(
"ERROR (Context::hideObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4305 objects.at(ObjID)->ishidden =
true;
4306 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4309 helios_runtime_error(
"ERROR (Context::hideObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4312 primitives.at(UUID)->ishidden =
true;
4317 for (
uint ObjID: ObjIDs) {
4325 helios_runtime_error(
"ERROR (Context::showObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4328 objects.at(ObjID)->ishidden =
false;
4329 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4332 helios_runtime_error(
"ERROR (Context::showObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4335 primitives.at(UUID)->ishidden =
false;
4340 for (
uint ObjID: ObjIDs) {
4347 helios_runtime_error(
"ERROR (Context::isObjectHidden): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4349 return objects.at(ObjID)->ishidden;
4353 return getObjectPointer_private(ObjID)->
getArea();
4358 if (objects.find(ObjID) == objects.end()) {
4359 helios_runtime_error(
"ERROR (Context::getObjectAverageNormal): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4363 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4366 for (
uint UUID: UUIDs) {
4395 for (
uint ObjID: ObjIDs) {
4409 vec3 newN = normalize(new_normal);
4412 float d = std::clamp(oldN * newN, -1.f, 1.f);
4413 float angle = acosf(d);
4417 axis = (std::abs(oldN.
x) < std::abs(oldN.
z)) ?
cross(oldN, {1, 0, 0}) :
cross(oldN, {0, 0, 1});
4429 vec3 localX{1, 0, 0};
4436 vec3 worldX{1, 0, 0};
4437 vec3 targ = worldX - newN * (newN * worldX);
4438 targ = normalize(targ);
4441 float twist = atan2f(newN *
cross(t1, targ),
4455 objects.at(ObjID)->object_origin = origin;
4459 return getObjectPointer_private(ObjID)->
hasTexture();
4463 getObjectPointer_private(ObjID)->
setColor(color);
4467 for (
const uint ObjID: ObjIDs) {
4468 getObjectPointer_private(ObjID)->
setColor(color);
4473 getObjectPointer_private(ObjID)->
setColor(color);
4477 for (
const uint ObjID: ObjIDs) {
4478 getObjectPointer_private(ObjID)->
setColor(color);
4491 for (
uint ObjID: ObjIDs) {
4501 for (
uint ObjID: ObjIDs) {
4507 const std::vector ObjIDs{ObjID};
4513 for (
uint ObjID: ObjIDs) {
4514 if (objects.find(ObjID) == objects.end()) {
4515 helios_runtime_error(
"ERROR (Context::getObjectBoundingBox): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4518 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4521 for (
const uint UUID: UUIDs) {
4524 if (p == 0 && o == 0) {
4525 min_corner = vertices.front();
4526 max_corner = min_corner;
4531 for (
const vec3 &vert: vertices) {
4532 if (vert.x < min_corner.
x) {
4533 min_corner.
x = vert.x;
4535 if (vert.y < min_corner.
y) {
4536 min_corner.
y = vert.y;
4538 if (vert.z < min_corner.
z) {
4539 min_corner.
z = vert.z;
4541 if (vert.x > max_corner.
x) {
4542 max_corner.
x = vert.x;
4544 if (vert.y > max_corner.
y) {
4545 max_corner.
y = vert.y;
4547 if (vert.z > max_corner.
z) {
4548 max_corner.
z = vert.z;
4557Tile *Context::getTileObjectPointer_private(
uint ObjID)
const {
4559 if (objects.find(ObjID) == objects.end()) {
4560 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4561 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TILE) {
4562 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tile Object.");
4565 return dynamic_cast<Tile *
>(objects.at(ObjID));
4568Sphere *Context::getSphereObjectPointer_private(
uint ObjID)
const {
4570 if (objects.find(ObjID) == objects.end()) {
4571 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4572 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_SPHERE) {
4573 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Sphere Object.");
4576 return dynamic_cast<Sphere *
>(objects.at(ObjID));
4579Tube *Context::getTubeObjectPointer_private(
uint ObjID)
const {
4581 if (objects.find(ObjID) == objects.end()) {
4582 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4583 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TUBE) {
4584 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tube Object.");
4587 return dynamic_cast<Tube *
>(objects.at(ObjID));
4590Box *Context::getBoxObjectPointer_private(
uint ObjID)
const {
4592 if (objects.find(ObjID) == objects.end()) {
4593 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4594 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_BOX) {
4595 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Box Object.");
4598 return dynamic_cast<Box *
>(objects.at(ObjID));
4601Disk *Context::getDiskObjectPointer_private(
uint ObjID)
const {
4603 if (objects.find(ObjID) == objects.end()) {
4604 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4605 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_DISK) {
4606 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Disk Object.");
4609 return dynamic_cast<Disk *
>(objects.at(ObjID));
4612Polymesh *Context::getPolymeshObjectPointer_private(
uint ObjID)
const {
4614 if (objects.find(ObjID) == objects.end()) {
4615 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4616 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_POLYMESH) {
4617 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Polymesh Object.");
4620 return dynamic_cast<Polymesh *
>(objects.at(ObjID));
4623Cone *Context::getConeObjectPointer_private(
uint ObjID)
const {
4625 if (objects.find(ObjID) == objects.end()) {
4626 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4627 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_CONE) {
4628 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Cone Object.");
4631 return dynamic_cast<Cone *
>(objects.at(ObjID));
4635 return getTileObjectPointer_private(ObjID)->
getCenter();
4639 return getTileObjectPointer_private(ObjID)->
getSize();
4647 return getTileObjectPointer_private(ObjID)->
getNormal();
4651 return getTileObjectPointer_private(ObjID)->
getTextureUV();
4655 return getTileObjectPointer_private(ObjID)->
getVertices();
4659 return getSphereObjectPointer_private(ObjID)->
getCenter();
4663 return getSphereObjectPointer_private(ObjID)->
getRadius();
4671 return getSphereObjectPointer_private(ObjID)->
getVolume();
4679 return getTubeObjectPointer_private(ObjID)->
getNodes();
4683 return getTubeObjectPointer_private(ObjID)->
getNodeCount();
4687 return getTubeObjectPointer_private(ObjID)->
getNodeRadii();
4691 return getTubeObjectPointer_private(ObjID)->
getNodeColors();
4695 return getTubeObjectPointer_private(ObjID)->
getVolume();
4699 return getTubeObjectPointer_private(ObjID)->
getSegmentVolume(segment_index);
4704 if (objects.find(ObjID) == objects.end()) {
4705 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4713 if (objects.find(ObjID) == objects.end()) {
4714 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4717 dynamic_cast<Tube *
>(objects.at(ObjID))->
appendTubeSegment(node_position, node_radius, texturefile, textureuv_ufrac);
4722 if (objects.find(ObjID) == objects.end()) {
4723 helios_runtime_error(
"ERROR (Context::scaleTubeGirth): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4731 if (objects.find(ObjID) == objects.end()) {
4732 helios_runtime_error(
"ERROR (Context::setTubeRadii): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4740 if (objects.find(ObjID) == objects.end()) {
4741 helios_runtime_error(
"ERROR (Context::scaleTubeLength): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4749 if (objects.find(ObjID) == objects.end()) {
4750 helios_runtime_error(
"ERROR (Context::pruneTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4758 if (objects.find(ObjID) == objects.end()) {
4759 helios_runtime_error(
"ERROR (Context::setTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4766 return getBoxObjectPointer_private(ObjID)->
getCenter();
4770 return getBoxObjectPointer_private(ObjID)->
getSize();
4778 return getBoxObjectPointer_private(ObjID)->
getVolume();
4782 return getDiskObjectPointer_private(ObjID)->
getCenter();
4786 return getDiskObjectPointer_private(ObjID)->
getSize();
4802 return getConeObjectPointer_private(ObjID)->
getNodeRadii();
4810 return getConeObjectPointer_private(ObjID)->
getNodeRadius(number);
4818 return getConeObjectPointer_private(ObjID)->
getLength();
4822 return getConeObjectPointer_private(ObjID)->
getVolume();
4826 getConeObjectPointer_private(ObjID)->
scaleLength(scale_factor);
4830 getConeObjectPointer_private(ObjID)->
scaleGirth(scale_factor);
4834 return getPolymeshObjectPointer_private(ObjID)->
getVolume();
4838 api_warnings.
report(std::cerr);