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);
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);
857 float local_xmin = 1e8, local_xmax = -1e8;
858 float local_ymin = 1e8, local_ymax = -1e8;
859 float local_zmin = 1e8, local_zmax = -1e8;
862#pragma omp for nowait
863 for (
int i = 0; i < (int) UUIDs.size(); i++) {
865 const std::vector<vec3> &verts = getPrimitivePointer_private(UUIDs[i])->getVertices();
867 for (
const auto &vert: verts) {
868 local_xmin = std::min(local_xmin, vert.x);
869 local_xmax = std::max(local_xmax, vert.x);
870 local_ymin = std::min(local_ymin, vert.y);
871 local_ymax = std::max(local_ymax, vert.y);
872 local_zmin = std::min(local_zmin, vert.z);
873 local_zmax = std::max(local_zmax, vert.z);
880 xbounds.
x = std::min(xbounds.
x, local_xmin);
881 xbounds.
y = std::max(xbounds.
y, local_xmax);
882 ybounds.
x = std::min(ybounds.
x, local_ymin);
883 ybounds.
y = std::max(ybounds.
y, local_ymax);
884 zbounds.
x = std::min(zbounds.
x, local_zmin);
885 zbounds.
y = std::max(zbounds.
y, local_zmax);
891 for (
uint UUID: UUIDs) {
892 const std::vector<vec3> &verts = getPrimitivePointer_private(UUID)->getVertices();
894 for (
auto &vert: verts) {
895 if (vert.x < xbounds.
x) {
897 }
else if (vert.x > xbounds.
y) {
900 if (vert.y < ybounds.
x) {
902 }
else if (vert.y > ybounds.
y) {
905 if (vert.z < zbounds.
x) {
907 }
else if (vert.z > zbounds.
y) {
917 vec2 xbounds, ybounds, zbounds;
920 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
921 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
922 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
924 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
928 vec2 xbounds, ybounds, zbounds;
931 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
932 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
933 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
935 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
939 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
941 for (
uint p: UUIDs_all) {
942 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
944 for (
auto &vertex: vertices) {
945 if (vertex.x < xbounds.
x || vertex.x > xbounds.
y) {
953 std::cerr <<
"WARNING (Context::cropDomainX): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
958 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
960 for (
uint p: UUIDs_all) {
961 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
963 for (
auto &vertex: vertices) {
964 if (vertex.y < ybounds.
x || vertex.y > ybounds.
y) {
972 std::cerr <<
"WARNING (Context::cropDomainY): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
977 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
979 for (
uint p: UUIDs_all) {
980 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
982 for (
auto &vertex: vertices) {
983 if (vertex.z < zbounds.
x || vertex.z > zbounds.
y) {
991 std::cerr <<
"WARNING (Context::cropDomainZ): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
996 size_t delete_count = 0;
997 for (
uint UUID: UUIDs) {
998 const std::vector<vec3> &vertices = getPrimitivePointer_private(UUID)->getVertices();
1000 for (
auto &vertex: vertices) {
1001 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) {
1009 if (delete_count == UUIDs.size()) {
1010 std::cerr <<
"WARNING (Context::cropDomain): No specified primitives were entirely inside cropped area, and thus all specified primitives were deleted." << std::endl;
1018 cropDomain(UUIDs, xbounds, ybounds, zbounds);
1025 helios_runtime_error(
"ERROR (Context::areObjectPrimitivesComplete): Object ID of " + std::to_string(objID) +
" does not exist in the context.");
1032 for (
auto it = objIDs.begin(); it != objIDs.end();) {
1034 it = objIDs.erase(it);
1042 for (
auto &vec: objIDs) {
1043 for (
auto it = vec.begin(); it != vec.end();) {
1054 for (
auto &vec2D: objIDs) {
1055 for (
auto &vec: vec2D) {
1056 for (
auto it = vec.begin(); it != vec.end();) {
1068 return objects.size();
1072 return objects.find(ObjID) != objects.end();
1076 std::vector<uint> objIDs;
1077 objIDs.reserve(objects.size());
1079 for (
auto [objID,
object]: objects) {
1083 objIDs.push_back(objID);
1090 for (
const uint ObjID: ObjIDs) {
1096 if (objects.find(ObjID) == objects.end()) {
1097 helios_runtime_error(
"ERROR (Context::deleteObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1102 for (
const auto &[label, type]:
obj->object_data_types) {
1103 decrementObjectDataLabelCounter(label);
1106 const std::vector<uint> &UUIDs =
obj->getPrimitiveUUIDs();
1110 objects.erase(ObjID);
1116 std::vector<uint> ObjIDs_copy(ObjIDs.size());
1118 for (
uint ObjID: ObjIDs) {
1127 if (objects.find(ObjID) == objects.end()) {
1128 helios_runtime_error(
"ERROR (Context::copyObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1131 ObjectType type = objects.at(ObjID)->getObjectType();
1133 const std::vector<uint> &UUIDs = getObjectPointer_private(ObjID)->
getPrimitiveUUIDs();
1136 for (
uint p: UUIDs_copy) {
1137 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1140 const std::string &texturefile = objects.at(ObjID)->getTextureFile();
1143 Tile *o = getTileObjectPointer_private(ObjID);
1147 auto *tile_new = (
new Tile(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1149 objects[currentObjectID] = tile_new;
1151 Sphere *o = getSphereObjectPointer_private(ObjID);
1155 auto *sphere_new = (
new Sphere(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1157 objects[currentObjectID] = sphere_new;
1159 Tube *o = getTubeObjectPointer_private(ObjID);
1161 const std::vector<vec3> &nodes = o->
getNodes();
1167 auto *tube_new = (
new Tube(currentObjectID, UUIDs_copy, nodes, radius, colors, triangle_vertices, subdiv, texturefile.c_str(),
this));
1169 objects[currentObjectID] = tube_new;
1171 Box *o = getBoxObjectPointer_private(ObjID);
1175 auto *box_new = (
new Box(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1177 objects[currentObjectID] = box_new;
1179 Disk *o = getDiskObjectPointer_private(ObjID);
1183 auto *disk_new = (
new Disk(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1185 objects[currentObjectID] = disk_new;
1187 auto *polymesh_new = (
new Polymesh(currentObjectID, UUIDs_copy, texturefile.c_str(),
this));
1189 objects[currentObjectID] = polymesh_new;
1191 Cone *o = getConeObjectPointer_private(ObjID);
1197 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));
1199 objects[currentObjectID] = cone_new;
1210 return currentObjectID - 1;
1214 std::vector<uint> output_object_IDs;
1215 output_object_IDs.resize(IDs.size());
1216 uint passed_count = 0;
1218 for (
uint i = 0; i < IDs.size(); i++) {
1224 if (strcmp(comparator,
"<") == 0) {
1225 if (
float(
R) < threshold) {
1226 output_object_IDs.at(passed_count) = IDs.at(i);
1229 }
else if (strcmp(comparator,
">") == 0) {
1230 if (
float(
R) > threshold) {
1231 output_object_IDs.at(passed_count) = IDs.at(i);
1234 }
else if (strcmp(comparator,
"=") == 0) {
1235 if (
float(
R) == threshold) {
1236 output_object_IDs.at(passed_count) = IDs.at(i);
1244 if (strcmp(comparator,
"<") == 0) {
1245 if (
R < threshold) {
1246 output_object_IDs.at(passed_count) = IDs.at(i);
1249 }
else if (strcmp(comparator,
">") == 0) {
1250 if (
R > threshold) {
1251 output_object_IDs.at(passed_count) = IDs.at(i);
1254 }
else if (strcmp(comparator,
"=") == 0) {
1255 if (
R == threshold) {
1256 output_object_IDs.at(passed_count) = IDs.at(i);
1264 if (strcmp(comparator,
"<") == 0) {
1265 if (
float(
R) < threshold) {
1266 output_object_IDs.at(passed_count) = IDs.at(i);
1269 }
else if (strcmp(comparator,
">") == 0) {
1270 if (
float(
R) > threshold) {
1271 output_object_IDs.at(passed_count) = IDs.at(i);
1274 }
else if (strcmp(comparator,
"=") == 0) {
1275 if (
float(
R) == threshold) {
1276 output_object_IDs.at(passed_count) = IDs.at(i);
1281 std::cerr <<
"WARNING: Object data not of type UINT, INT, or FLOAT. Filtering for other types not yet supported." << std::endl;
1286 output_object_IDs.resize(passed_count);
1288 return output_object_IDs;
1294 helios_runtime_error(
"ERROR (Context::translateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1297 getObjectPointer_private(ObjID)->
translate(shift);
1301 for (
uint ID: ObjIDs) {
1309 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1312 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_xyz);
1315void Context::rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const char *rotation_axis_xyz)
const {
1316 for (
uint ID: ObjIDs) {
1324 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1327 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_vector);
1331 for (
uint ID: ObjIDs) {
1332 rotateObject(ID, rotation_radians, rotation_axis_vector);
1339 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1342 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_origin, rotation_axis_vector);
1346 for (
uint ID: ObjIDs) {
1347 rotateObject(ID, rotation_radians, rotation_origin, rotation_axis_vector);
1354 helios_runtime_error(
"ERROR (Context::rotateObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1357 getObjectPointer_private(ObjID)->
rotate(rotation_radians, objects.at(ObjID)->object_origin, rotation_axis_vector);
1361 for (
uint ID: ObjIDs) {
1362 rotateObject(ID, rotation_radians, objects.at(ID)->object_origin, rotation_axis_vector);
1369 helios_runtime_error(
"ERROR (Context::scaleObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1372 getObjectPointer_private(ObjID)->
scale(scalefact);
1376 for (
uint ID: ObjIDs) {
1384 helios_runtime_error(
"ERROR (Context::scaleObjectAboutCenter): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1391 for (
uint ID: ObjIDs) {
1399 helios_runtime_error(
"ERROR (Context::scaleObjectAboutPoint): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1406 for (
uint ID: ObjIDs) {
1414 helios_runtime_error(
"ERROR (Context::scaleObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1417 getObjectPointer_private(ObjID)->
scaleAboutPoint(scalefact, objects.at(ObjID)->object_origin);
1421 for (
uint ID: ObjIDs) {
1429 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1435 std::vector<uint> UUIDs;
1439 UUIDs.push_back(UUID);
1449 std::vector<uint> output_UUIDs;
1451 for (
uint ObjID: ObjIDs) {
1454 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1458 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1460 return output_UUIDs;
1464 std::vector<uint> output_UUIDs;
1466 for (
uint j = 0; j < ObjIDs.size(); j++) {
1467 for (
uint i = 0; i < ObjIDs.at(j).size(); i++) {
1470 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjIDs.at(j).at(i)) +
" not found in the context.");
1474 const std::vector<uint> ¤t_UUIDs = getObjectPointer_private(ObjIDs.at(j).at(i))->
getPrimitiveUUIDs();
1475 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1478 return output_UUIDs;
1487 helios_runtime_error(
"ERROR (Context::getObjectType): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1496 helios_runtime_error(
"ERROR (Context::getTileObjectAreaRatio): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1500 std::cerr <<
"WARNING (Context::getTileObjectAreaRatio): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1504 if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1505 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;
1509 if (subdiv.
x == 1 && subdiv.
y == 1) {
1513 float area = getTileObjectPointer_private(ObjID)->
getArea();
1514 const vec2 size = getTileObjectPointer_private(ObjID)->
getSize();
1516 float subpatch_area = size.
x * size.
y / scast<float>(subdiv.
x * subdiv.
y);
1517 return area / subpatch_area;
1521 std::vector<float> AreaRatios(ObjIDs.size());
1522 for (
uint i = 0; i < ObjIDs.size(); i++) {
1531 std::vector<uint> tile_ObjectIDs;
1532 std::vector<uint> textured_tile_ObjectIDs;
1535 std::vector<std::string> tex;
1537 for (
uint ObjID: ObjIDs) {
1540 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1546 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1547 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1548 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is missing primitives. Skipping..." << std::endl;
1551 Patch *p = getPatchPointer_private(getObjectPointer_private(ObjID)->getPrimitiveUUIDs().at(0));
1552 if (!p->hasTexture()) {
1553 tile_ObjectIDs.push_back(ObjID);
1555 textured_tile_ObjectIDs.push_back(ObjID);
1556 tex.push_back(p->getTextureFile());
1562 for (
unsigned int tile_ObjectID: tile_ObjectIDs) {
1563 Tile *current_object_pointer = getTileObjectPointer_private(tile_ObjectID);
1564 const std::vector<uint> &UUIDs_old = current_object_pointer->
getPrimitiveUUIDs();
1572 std::vector<uint> UUIDs_new =
addTile(center, size, rotation, new_subdiv, color);
1574 for (
uint UUID: UUIDs_new) {
1575 getPrimitivePointer_private(UUID)->setParentObjectID(tile_ObjectID);
1584 sort(tex.begin(), tex.end());
1585 std::vector<std::string>::iterator it;
1586 it = std::unique(tex.begin(), tex.end());
1587 tex.resize(std::distance(tex.begin(), it));
1590 std::vector<uint> object_templates;
1591 std::vector<std::vector<uint>> template_primitives;
1592 for (
uint j = 0; j < tex.size(); j++) {
1595 object_templates.emplace_back(object_template);
1596 std::vector<uint> object_primitives = getTileObjectPointer_private(object_template)->
getPrimitiveUUIDs();
1597 template_primitives.emplace_back(object_primitives);
1602 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1604 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1605 std::string current_texture_file = current_object_pointer->
getTextureFile();
1615 for (
uint j = 0; j < tex.size(); j++) {
1617 if (current_texture_file == tex.at(j)) {
1619 std::vector<uint> new_primitives =
copyPrimitive(template_primitives.at(j));
1642 current_object_pointer->
translate(center);
1654 std::vector<uint> tile_ObjectIDs;
1655 std::vector<uint> textured_tile_ObjectIDs;
1657 std::vector<std::string> tex;
1659 for (
uint ObjID: ObjIDs) {
1662 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1668 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1669 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1670 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is missing primitives. Skipping..." << std::endl;
1673 Patch *p = getPatchPointer_private(getObjectPointer_private(ObjID)->getPrimitiveUUIDs().at(0));
1674 if (!p->hasTexture()) {
1675 tile_ObjectIDs.push_back(ObjID);
1677 textured_tile_ObjectIDs.push_back(ObjID);
1678 tex.push_back(p->getTextureFile());
1684 for (
uint i = 0; i < tile_ObjectIDs.size(); i++) {
1685 Tile *current_object_pointer = getTileObjectPointer_private(tile_ObjectIDs.at(i));
1694 float tile_area = current_object_pointer->
getArea();
1697 float subpatch_dimension = sqrtf(tile_area / area_ratio);
1698 float subpatch_per_x = size.
x / subpatch_dimension;
1699 float subpatch_per_y = size.
y / subpatch_dimension;
1701 float option_1_AR = (tile_area / (size.
x / ceil(subpatch_per_x) * size.
y / floor(subpatch_per_y))) - area_ratio;
1702 float option_2_AR = (tile_area / (size.
x / floor(subpatch_per_x) * size.
y / ceil(subpatch_per_y))) - area_ratio;
1705 if ((
int) area_ratio == 1) {
1707 }
else if (option_1_AR >= option_2_AR) {
1708 new_subdiv =
make_int2(ceil(subpatch_per_x), floor(subpatch_per_y));
1710 new_subdiv =
make_int2(floor(subpatch_per_x), ceil(subpatch_per_y));
1714 std::vector<uint> UUIDs_new =
addTile(center, size, rotation, new_subdiv, color);
1716 for (
uint UUID: UUIDs_new) {
1717 getPrimitivePointer_private(UUID)->setParentObjectID(tile_ObjectIDs.at(i));
1726 sort(tex.begin(), tex.end());
1727 std::vector<std::string>::iterator it;
1728 it = std::unique(tex.begin(), tex.end());
1729 tex.resize(std::distance(tex.begin(), it));
1735 std::vector<uint> object_templates;
1736 std::vector<std::vector<uint>> template_primitives;
1737 for (
uint j = 0; j < tex.size(); j++) {
1740 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1742 Tile *current_object_pointer_b = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1743 std::string current_texture_file_b = current_object_pointer_b->
getTextureFile();
1745 if (current_texture_file_b == tex.at(j)) {
1752 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(ii));
1753 vec2 tile_size = current_object_pointer->
getSize();
1754 float tile_area = current_object_pointer->
getArea();
1757 float subpatch_dimension = sqrtf(tile_area / area_ratio);
1758 float subpatch_per_x = tile_size.
x / subpatch_dimension;
1759 float subpatch_per_y = tile_size.
y / subpatch_dimension;
1761 float option_1_AR = (tile_area / (tile_size.
x / ceil(subpatch_per_x) * tile_size.
y / floor(subpatch_per_y))) - area_ratio;
1762 float option_2_AR = (tile_area / (tile_size.
x / floor(subpatch_per_x) * tile_size.
y / ceil(subpatch_per_y))) - area_ratio;
1765 if ((
int) area_ratio == 1) {
1767 }
else if (option_1_AR >= option_2_AR) {
1768 new_subdiv =
make_int2(ceil(subpatch_per_x), floor(subpatch_per_y));
1770 new_subdiv =
make_int2(floor(subpatch_per_x), ceil(subpatch_per_y));
1775 object_templates.emplace_back(object_template);
1776 std::vector<uint> object_primitives = getTileObjectPointer_private(object_template)->
getPrimitiveUUIDs();
1777 template_primitives.emplace_back(object_primitives);
1782 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1784 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1786 std::string current_texture_file = current_object_pointer->
getTextureFile();
1796 for (
uint j = 0; j < tex.size(); j++) {
1798 if (current_texture_file == tex.at(j)) {
1800 std::vector<uint> new_primitives =
copyPrimitive(template_primitives.at(j));
1824 current_object_pointer->
translate(center);
1837 return addSphere(Ndivs, center, radius, color);
1841 std::vector<uint> UUID;
1843 float dtheta =
PI_F / float(Ndivs);
1844 float dphi = 2.0f *
PI_F / float(Ndivs);
1847 for (
int j = 0; j < Ndivs; j++) {
1856 for (
int j = 0; j < Ndivs; j++) {
1865 for (
int j = 0; j < Ndivs; j++) {
1866 for (
int i = 1; i < Ndivs - 1; i++) {
1881 if (!validateTextureFileExtenstion(texturefile)) {
1882 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1883 }
else if (!doesTextureFileExist(texturefile)) {
1884 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" does not exist.");
1887 std::vector<uint> UUID;
1889 float dtheta =
PI_F / float(Ndivs);
1890 float dphi = 2.0f *
PI_F / float(Ndivs);
1893 for (
int j = 0; j < Ndivs; j++) {
1898 vec3 n0 = v0 - center;
1900 vec3 n1 = v1 - center;
1902 vec3 n2 = v2 - center;
1905 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);
1906 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);
1907 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);
1909 if (j == Ndivs - 1) {
1913 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1915 UUID.push_back(triangle_uuid);
1922 for (
int j = 0; j < Ndivs; j++) {
1927 vec3 n0 = v0 - center;
1929 vec3 n1 = v1 - center;
1931 vec3 n2 = v2 - center;
1934 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);
1935 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);
1936 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);
1938 if (j == Ndivs - 1) {
1942 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1944 UUID.push_back(triangle_uuid);
1951 for (
int j = 0; j < Ndivs; j++) {
1952 for (
int i = 1; i < Ndivs - 1; i++) {
1958 vec3 n0 = v0 - center;
1960 vec3 n1 = v1 - center;
1962 vec3 n2 = v2 - center;
1964 vec3 n3 = v3 - center;
1967 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);
1968 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);
1969 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);
1970 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);
1972 if (j == Ndivs - 1) {
1977 uint triangle_uuid1 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1979 UUID.push_back(triangle_uuid1);
1983 uint triangle_uuid2 =
addTriangle(v0, v2, v3, texturefile, uv0, uv2, uv3);
1985 UUID.push_back(triangle_uuid2);
1998 return addTile(center, size, rotation, subdiv, color);
2003 subsize.
x = size.
x / float(subdiv.
x);
2004 subsize.
y = size.
y / float(subdiv.
y);
2006 std::vector<uint> UUID(subdiv.
x * subdiv.
y);
2009 for (
uint j = 0; j < subdiv.
y; j++) {
2010 for (
uint i = 0; i < subdiv.
x; i++) {
2011 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);
2016 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
elevation,
"x");
2018 if (rotation.
azimuth != 0.f) {
2019 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
azimuth,
"z");
2021 getPrimitivePointer_private(UUID[t])->translate(center);
2031 return addTile(center, size, rotation, subdiv, texturefile,
make_int2(1, 1));
2035 if (!validateTextureFileExtenstion(texturefile)) {
2036 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2037 }
else if (!doesTextureFileExist(texturefile)) {
2038 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" does not exist.");
2039 }
else if (texture_repeat.
x < 1 || texture_repeat.
y < 1) {
2040 helios_runtime_error(
"ERROR (Context::addTile): Number of texture repeats must be greater than 0.");
2044 int2 repeat = texture_repeat;
2045 repeat.
x = std::min(subdiv.
x, repeat.
x);
2046 repeat.
y = std::min(subdiv.
y, repeat.
y);
2047 while (subdiv.
x % repeat.
x != 0) {
2050 while (subdiv.
y % repeat.
y != 0) {
2054 std::vector<uint> UUID;
2057 subsize.
x = size.
x / float(subdiv.
x);
2058 subsize.
y = size.
y / float(subdiv.
y);
2060 std::vector<helios::vec2> uv(4);
2061 int2 sub_per_repeat;
2062 sub_per_repeat.
x = subdiv.
x / repeat.
x;
2063 sub_per_repeat.
y = subdiv.
y / repeat.
y;
2065 uv_sub.
x = 1.f / float(sub_per_repeat.
x);
2066 uv_sub.
y = 1.f / float(sub_per_repeat.
y);
2068 addTexture(texturefile);
2070 const int2 &sz = textures.at(texturefile).getImageResolution();
2071 if (subdiv.
x >= repeat.
x * sz.
x || subdiv.
y >= repeat.
y * sz.
y) {
2072 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.");
2075 for (
uint j = 0; j < subdiv.
y; j++) {
2076 for (
uint i = 0; i < subdiv.
x; i++) {
2077 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);
2079 uint i_local = i % sub_per_repeat.
x;
2080 uint j_local = j % sub_per_repeat.
y;
2081 uv.at(0) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local) * uv_sub.
y);
2082 uv.at(1) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local) * uv_sub.
y);
2083 uv.at(2) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
2084 uv.at(3) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
2086 auto *patch_new = (
new Patch(texturefile, uv, textures, 0, currentUUID));
2088 if (patch_new->getSolidFraction() == 0) {
2093 assert(size.
x > 0.f && size.
y > 0.f);
2094 patch_new->scale(
make_vec3(subsize.
x, subsize.
y, 1));
2096 patch_new->translate(subcenter);
2099 patch_new->rotate(-rotation.
elevation,
"x");
2102 patch_new->rotate(-rotation.
azimuth,
"z");
2105 patch_new->translate(center);
2107 primitives[currentUUID] = patch_new;
2110 patch_new->context_ptr =
this;
2111 patch_new->materialID = 0;
2113 materials[0].reference_count++;
2116 UUID.push_back(currentUUID - 1);
2124 std::vector<RGBcolor> color(nodes.size(),
make_RGBcolor(0.f, 0.75f, 0.f));
2126 return addTube(Ndivs, nodes, radius, color);
2129std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const std::vector<RGBcolor> &color) {
2130 const uint node_count = nodes.size();
2132 if (node_count == 0) {
2134 }
else if (node_count != radius.size()) {
2135 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2136 }
else if (node_count != color.size()) {
2137 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `color' arguments must agree.");
2141 std::vector<float> cfact(radial_subdivisions + 1);
2142 std::vector<float> sfact(radial_subdivisions + 1);
2143 std::vector<std::vector<vec3>> xyz;
2146 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2148 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2149 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2150 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2153 for (
int i = 0; i < node_count; i++) {
2155 if (radius.at(i) < 0) {
2160 vec.
x = nodes[i + 1].x - nodes[i].x;
2161 vec.
y = nodes[i + 1].y - nodes[i].y;
2162 vec.
z = nodes[i + 1].z - nodes[i].z;
2163 }
else if (i == node_count - 1) {
2164 vec.
x = nodes[i].x - nodes[i - 1].x;
2165 vec.
y = nodes[i].y - nodes[i - 1].y;
2166 vec.
z = nodes[i].z - nodes[i - 1].z;
2168 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2169 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2170 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2175 if (fabs(nvec * vec) > 0.95f) {
2176 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2177 if (fabs(nvec * vec) > 0.95f) {
2178 nvec =
vec3(1.0f, 0.0f, 0.0f);
2182 if (fabs(vec.z) > 0.95f) {
2183 nvec =
vec3(1.0f, 0.0f, 0.0f);
2186 convec =
cross(nvec, vec);
2188 nvec =
cross(vec, convec);
2191 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2193 normal.
x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2194 normal.
y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2195 normal.
z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2197 xyz[j][i].x = nodes[i].x + normal.
x;
2198 xyz[j][i].y = nodes[i].y + normal.
y;
2199 xyz[j][i].z = nodes[i].z + normal.
z;
2204 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2207 for (
int i = 0; i < node_count - 1; i++) {
2208 for (
int j = 0; j < radial_subdivisions; j++) {
2210 v1 = xyz[j + 1][i + 1];
2213 UUIDs.at(ii) =
addTriangle(v0, v1, v2, color.at(i));
2217 v2 = xyz[j + 1][i + 1];
2219 UUIDs.at(ii + 1) =
addTriangle(v0, v1, v2, color.at(i));
2228std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile) {
2229 if (!validateTextureFileExtenstion(texturefile)) {
2230 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2231 }
else if (!doesTextureFileExist(texturefile)) {
2232 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" does not exist.");
2235 const uint node_count = nodes.size();
2237 if (node_count == 0) {
2239 }
else if (node_count != radius.size()) {
2240 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2244 std::vector<float> cfact(radial_subdivisions + 1);
2245 std::vector<float> sfact(radial_subdivisions + 1);
2246 std::vector<std::vector<vec3>> xyz, normal;
2247 std::vector<std::vector<vec2>> uv;
2252 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2254 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2255 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2256 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2259 for (
int i = 0; i < node_count; i++) {
2261 if (radius.at(i) < 0) {
2266 vec.
x = nodes[i + 1].x - nodes[i].x;
2267 vec.
y = nodes[i + 1].y - nodes[i].y;
2268 vec.
z = nodes[i + 1].z - nodes[i].z;
2269 }
else if (i == node_count - 1) {
2270 vec.
x = nodes[i].x - nodes[i - 1].x;
2271 vec.
y = nodes[i].y - nodes[i - 1].y;
2272 vec.
z = nodes[i].z - nodes[i - 1].z;
2274 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2275 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2276 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2281 if (fabs(nvec * vec) > 0.95f) {
2282 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2283 if (fabs(nvec * vec) > 0.95f) {
2284 nvec =
vec3(1.0f, 0.0f, 0.0f);
2288 if (fabs(vec.z) > 0.95f) {
2289 nvec =
vec3(1.0f, 0.0f, 0.0f);
2292 convec =
cross(nvec, vec);
2294 nvec =
cross(vec, convec);
2297 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2298 normal[j][i].
x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2299 normal[j][i].y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2300 normal[j][i].z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2302 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2303 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2304 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2306 uv[j][i].x = float(i) / float(node_count - 1);
2307 uv[j][i].y = float(j) / float(radial_subdivisions);
2309 normal[j][i] = normal[j][i] / radius[i];
2315 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2318 for (
int i = 0; i < node_count - 1; i++) {
2319 for (
int j = 0; j < radial_subdivisions; j++) {
2321 v1 = xyz[j + 1][i + 1];
2325 uv1 = uv[j + 1][i + 1];
2328 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2330 UUIDs.at(ii) = triangle_uuid;
2338 v2 = xyz[j + 1][i + 1];
2342 uv2 = uv[j + 1][i + 1];
2344 uint triangle_uuid2 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2346 UUIDs.at(ii + 1) = triangle_uuid2;
2349 UUIDs.at(ii + 1) = 0;
2357 UUIDs.erase(std::remove(UUIDs.begin(), UUIDs.end(), 0), UUIDs.end());
2365 return addBox(center, size, subdiv, color,
false);
2369 return addBox(center, size, subdiv, color,
false);
2373 return addBox(center, size, subdiv, texturefile,
false);
2377 std::vector<uint> UUID;
2380 subsize.
x = size.
x / float(subdiv.
x);
2381 subsize.
y = size.
y / float(subdiv.
y);
2382 subsize.
z = size.
z / float(subdiv.
z);
2385 std::vector<uint> U;
2387 if (reverse_normals) {
2392 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2394 UUID.insert(UUID.end(), U.begin(), U.end());
2397 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2399 UUID.insert(UUID.end(), U.begin(), U.end());
2404 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2406 UUID.insert(UUID.end(), U.begin(), U.end());
2409 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2411 UUID.insert(UUID.end(), U.begin(), U.end());
2416 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2418 UUID.insert(UUID.end(), U.begin(), U.end());
2421 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2423 UUID.insert(UUID.end(), U.begin(), U.end());
2429 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2431 UUID.insert(UUID.end(), U.begin(), U.end());
2434 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2436 UUID.insert(UUID.end(), U.begin(), U.end());
2441 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2443 UUID.insert(UUID.end(), U.begin(), U.end());
2446 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2448 UUID.insert(UUID.end(), U.begin(), U.end());
2453 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2455 UUID.insert(UUID.end(), U.begin(), U.end());
2458 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2460 UUID.insert(UUID.end(), U.begin(), U.end());
2467 if (!validateTextureFileExtenstion(texturefile)) {
2468 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2469 }
else if (!doesTextureFileExist(texturefile)) {
2470 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" does not exist.");
2473 std::vector<uint> UUID;
2476 subsize.
x = size.
x / float(subdiv.
x);
2477 subsize.
y = size.
y / float(subdiv.
y);
2478 subsize.
z = size.
z / float(subdiv.
z);
2481 std::vector<uint> U;
2483 if (reverse_normals) {
2488 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2490 UUID.insert(UUID.end(), U.begin(), U.end());
2493 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2495 UUID.insert(UUID.end(), U.begin(), U.end());
2500 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2502 UUID.insert(UUID.end(), U.begin(), U.end());
2505 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2507 UUID.insert(UUID.end(), U.begin(), U.end());
2512 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2514 UUID.insert(UUID.end(), U.begin(), U.end());
2517 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2519 UUID.insert(UUID.end(), U.begin(), U.end());
2525 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2527 UUID.insert(UUID.end(), U.begin(), U.end());
2530 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2532 UUID.insert(UUID.end(), U.begin(), U.end());
2537 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2539 UUID.insert(UUID.end(), U.begin(), U.end());
2542 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2544 UUID.insert(UUID.end(), U.begin(), U.end());
2549 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2551 UUID.insert(UUID.end(), U.begin(), U.end());
2554 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2556 UUID.insert(UUID.end(), U.begin(), U.end());
2587 std::vector<uint> UUID(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2589 for (
int r = 0; r < Ndivs.
y; r++) {
2590 for (
int t = 0; t < Ndivs.
x; t++) {
2591 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2592 float theta = dtheta * float(t);
2593 float theta_plus = dtheta * float(t + 1);
2595 float rx = size.
x / float(Ndivs.
y) * float(r);
2596 float ry = size.
y / float(Ndivs.
y) * float(r);
2598 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2599 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2604 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);
2606 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);
2608 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
elevation,
"y");
2609 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
azimuth,
"z");
2610 getPrimitivePointer_private(UUID.at(i))->translate(center);
2620 if (!validateTextureFileExtenstion(texturefile)) {
2621 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2622 }
else if (!doesTextureFileExist(texturefile)) {
2623 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" does not exist.");
2626 std::vector<uint> UUID;
2627 UUID.reserve(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2628 for (
int r = 0; r < Ndivs.
y; r++) {
2629 for (
int t = 0; t < Ndivs.
x; t++) {
2630 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2631 float theta = dtheta * float(t);
2632 float theta_plus = dtheta * float(t + 1);
2634 float rx = size.
x / float(Ndivs.
y) * float(r);
2635 float ry = size.
y / float(Ndivs.
y) * float(r);
2636 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2637 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2640 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),
2641 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
2642 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2644 UUID.push_back(triangle_uuid);
2650 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,
2651 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)),
2652 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)));
2654 UUID.push_back(triangle_uuid1);
2659 uint triangle_uuid2 =
2660 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,
2661 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)),
2662 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2664 UUID.push_back(triangle_uuid2);
2671 size_t start_idx = UUID.size() - (r == 0 ? 1 : 2);
2672 for (
size_t uuid_idx = start_idx; uuid_idx < UUID.size(); uuid_idx++) {
2673 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
elevation,
"y");
2674 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
azimuth,
"z");
2675 getPrimitivePointer_private(UUID.at(uuid_idx))->translate(center);
2687 return addCone(Ndivs, node0, node1, radius0, radius1, color);
2691 std::vector<helios::vec3> nodes{node0, node1};
2692 std::vector<float> radii{radius0, radius1};
2695 std::vector<float> cfact(Ndivs + 1);
2696 std::vector<float> sfact(Ndivs + 1);
2697 std::vector<std::vector<vec3>> xyz, normal;
2698 xyz.resize(Ndivs + 1);
2699 normal.resize(Ndivs + 1);
2700 for (
uint j = 0; j < Ndivs + 1; j++) {
2701 xyz.at(j).resize(2);
2702 normal.at(j).resize(2);
2704 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2706 for (
int j = 0; j < Ndivs + 1; j++) {
2707 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2708 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2711 for (
int i = 0; i < 2; i++) {
2714 vec.
x = nodes[i + 1].x - nodes[i].x;
2715 vec.
y = nodes[i + 1].y - nodes[i].y;
2716 vec.
z = nodes[i + 1].z - nodes[i].z;
2717 }
else if (i == 1) {
2718 vec.
x = nodes[i].x - nodes[i - 1].x;
2719 vec.
y = nodes[i].y - nodes[i - 1].y;
2720 vec.
z = nodes[i].z - nodes[i - 1].z;
2724 convec =
cross(nvec, vec);
2726 convec.
x = convec.
x / norm;
2727 convec.
y = convec.
y / norm;
2728 convec.
z = convec.
z / norm;
2729 nvec =
cross(vec, convec);
2731 nvec.
x = nvec.
x / norm;
2732 nvec.
y = nvec.
y / norm;
2733 nvec.
z = nvec.
z / norm;
2736 for (
int j = 0; j < Ndivs + 1; j++) {
2737 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2738 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2739 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2741 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2742 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2743 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2745 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];
2762 v2 = xyz[j + 1][i + 1];
2772 if (!validateTextureFileExtenstion(texturefile)) {
2773 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2774 }
else if (!doesTextureFileExist(texturefile)) {
2775 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" does not exist.");
2778 std::vector<helios::vec3> nodes{node0, node1};
2779 std::vector<float> radii{radius0, radius1};
2782 std::vector<float> cfact(Ndivs + 1);
2783 std::vector<float> sfact(Ndivs + 1);
2784 std::vector<std::vector<vec3>> xyz, normal;
2785 std::vector<std::vector<vec2>> uv;
2786 xyz.resize(Ndivs + 1);
2787 normal.resize(Ndivs + 1);
2788 uv.resize(Ndivs + 1);
2789 for (
uint j = 0; j < Ndivs + 1; j++) {
2790 xyz.at(j).resize(2);
2791 normal.at(j).resize(2);
2794 vec3 nvec(0.f, 1.f, 0.f);
2796 for (
int j = 0; j < Ndivs + 1; j++) {
2797 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2798 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2801 for (
int i = 0; i < 2; i++) {
2804 vec.
x = nodes[i + 1].x - nodes[i].x;
2805 vec.
y = nodes[i + 1].y - nodes[i].y;
2806 vec.
z = nodes[i + 1].z - nodes[i].z;
2807 }
else if (i == 1) {
2808 vec.
x = nodes[i].x - nodes[i - 1].x;
2809 vec.
y = nodes[i].y - nodes[i - 1].y;
2810 vec.
z = nodes[i].z - nodes[i - 1].z;
2814 convec =
cross(nvec, vec);
2816 convec.
x = convec.
x / norm;
2817 convec.
y = convec.
y / norm;
2818 convec.
z = convec.
z / norm;
2819 nvec =
cross(vec, convec);
2821 nvec.
x = nvec.
x / norm;
2822 nvec.
y = nvec.
y / norm;
2823 nvec.
z = nvec.
z / norm;
2825 for (
int j = 0; j < Ndivs + 1; j++) {
2826 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2827 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2828 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2830 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2831 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2832 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2834 uv[j][i].x = float(i) / float(2 - 1);
2835 uv[j][i].y = float(j) / float(Ndivs);
2837 normal[j][i] = normal[j][i] / radii[i];
2843 std::vector<uint> UUID;
2845 for (
int i = 0; i < 2 - 1; i++) {
2846 for (
int j = 0; j < Ndivs; j++) {
2848 v1 = xyz[j + 1][i + 1];
2852 uv1 = uv[j + 1][i + 1];
2855 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2856 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2858 UUID.push_back(triangle_uuid);
2866 v2 = xyz[j + 1][i + 1];
2870 uv2 = uv[j + 1][i + 1];
2872 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2873 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2875 UUID.push_back(triangle_uuid);
2891 std::map<uint, float> pcolor_data;
2894 float data_min_new = 9999999;
2895 float data_max_new = -9999999;
2896 for (
uint UUID: UUIDs) {
2898 warnings.
addWarning(
"primitive_does_not_exist",
"Primitive for UUID " + std::to_string(UUID) +
" does not exist. Skipping this primitive.");
2906 warnings.
addWarning(
"unsupported_data_type",
"Only primitive data types of int, uint, float, and double are supported for this function. Skipping this primitive.");
2917 dataf = float(data);
2921 dataf = float(data);
2925 dataf = float(data);
2929 if (data_min == 9999999 && data_max == -9999999) {
2930 if (dataf < data_min_new) {
2931 data_min_new = dataf;
2933 if (dataf > data_max_new) {
2934 data_max_new = dataf;
2938 pcolor_data[UUID] = dataf;
2941 if (data_min == 9999999 && data_max == -9999999) {
2942 data_min = data_min_new;
2943 data_max = data_max_new;
2948 std::map<std::string, std::vector<std::string>> cmap_texture_filenames;
2950 for (
auto &[UUID, pdata]: pcolor_data) {
2953 int cmap_ind = std::round((pdata - data_min) / (data_max - data_min) *
float(Ncolors - 1));
2957 }
else if (cmap_ind >= Ncolors) {
2958 cmap_ind = Ncolors - 1;
2975 warnings.
report(std::cerr);
2979 if (Ncolors > 9999) {
2980 std::cerr <<
"WARNING (Context::generateColormap): Truncating number of color map textures to maximum value of 9999." << std::endl;
2983 if (ctable.size() != cfrac.size()) {
2984 helios_runtime_error(
"ERROR (Context::generateColormap): The length of arguments 'ctable' and 'cfrac' must match.");
2986 if (ctable.empty()) {
2987 helios_runtime_error(
"ERROR (Context::generateColormap): 'ctable' and 'cfrac' arguments contain empty vectors.");
2990 std::vector<RGBcolor> color_table(Ncolors);
2992 for (
int i = 0; i < Ncolors; i++) {
2993 float frac = float(i) / float(Ncolors - 1) * cfrac.back();
2996 for (j = 0; j < cfrac.size() - 1; j++) {
2997 if (frac >= cfrac.at(j) && frac <= cfrac.at(j + 1)) {
3002 float cminus = std::fmaxf(0.f, cfrac.at(j));
3003 float cplus = std::fminf(1.f, cfrac.at(j + 1));
3005 float jfrac = (frac - cminus) / (cplus - cminus);
3008 color.
r = ctable.at(j).r + jfrac * (ctable.at(j + 1).r - ctable.at(j).r);
3009 color.
g = ctable.at(j).g + jfrac * (ctable.at(j + 1).g - ctable.at(j).g);
3010 color.
b = ctable.at(j).b + jfrac * (ctable.at(j + 1).b - ctable.at(j).b);
3012 color_table.at(i) = color;
3019 std::vector<RGBcolor> ctable_c;
3020 std::vector<float> clocs_c;
3022 if (colormap ==
"hot") {
3031 clocs_c.at(0) = 0.f;
3032 clocs_c.at(1) = 0.25f;
3033 clocs_c.at(2) = 0.5f;
3034 clocs_c.at(3) = 0.75f;
3035 clocs_c.at(4) = 1.f;
3036 }
else if (colormap ==
"cool") {
3038 ctable_c.at(0) = RGB::cyan;
3039 ctable_c.at(1) = RGB::magenta;
3042 clocs_c.at(0) = 0.f;
3043 clocs_c.at(1) = 1.f;
3044 }
else if (colormap ==
"lava") {
3053 clocs_c.at(0) = 0.f;
3054 clocs_c.at(1) = 0.4f;
3055 clocs_c.at(2) = 0.5f;
3056 clocs_c.at(3) = 0.6f;
3057 clocs_c.at(4) = 1.f;
3058 }
else if (colormap ==
"rainbow") {
3060 ctable_c.at(0) = RGB::navy;
3061 ctable_c.at(1) = RGB::cyan;
3062 ctable_c.at(2) = RGB::yellow;
3066 clocs_c.at(0) = 0.f;
3067 clocs_c.at(1) = 0.3f;
3068 clocs_c.at(2) = 0.7f;
3069 clocs_c.at(3) = 1.f;
3070 }
else if (colormap ==
"parula") {
3072 ctable_c.at(0) = RGB::navy;
3074 ctable_c.at(2) = RGB::goldenrod;
3075 ctable_c.at(3) = RGB::yellow;
3078 clocs_c.at(0) = 0.f;
3079 clocs_c.at(1) = 0.4f;
3080 clocs_c.at(2) = 0.7f;
3081 clocs_c.at(3) = 1.f;
3082 }
else if (colormap ==
"gray") {
3084 ctable_c.at(0) = RGB::black;
3085 ctable_c.at(1) = RGB::white;
3088 clocs_c.at(0) = 0.f;
3089 clocs_c.at(1) = 1.f;
3090 }
else if (colormap ==
"green") {
3092 ctable_c.at(0) = RGB::black;
3093 ctable_c.at(1) = RGB::green;
3096 clocs_c.at(0) = 0.f;
3097 clocs_c.at(1) = 1.f;
3099 helios_runtime_error(
"ERROR (Context::generateColormapTextures): Unknown colormap " + colormap +
".");
3106 uint Ncolors = colormap_data.size();
3109 std::ifstream tfile(texturefile);
3111 helios_runtime_error(
"ERROR (Context::generateTexturesFromColormap): Texture file " + texturefile +
" does not exist, or you do not have permission to read it.");
3121 std::vector<RGBcolor> color_table(Ncolors);
3123 std::vector<std::string> texture_filenames(Ncolors);
3125 if (file_ext ==
"png" || file_ext ==
"PNG") {
3126 std::vector<RGBAcolor> pixel_data;
3128 readPNG(texturefile, width, height, pixel_data);
3130 for (
int i = 0; i < Ncolors; i++) {
3131 std::ostringstream filename;
3132 filename <<
"lib/images/colormap_" << file_base <<
"_" << std::setw(4) << std::setfill(
'0') << std::to_string(i) <<
".png";
3134 texture_filenames.at(i) = filename.str();
3136 RGBcolor color = colormap_data.at(i);
3138 for (
int row = 0; row < height; row++) {
3139 for (
int col = 0; col < width; col++) {
3140 pixel_data.at(row * width + col) =
make_RGBAcolor(color, pixel_data.at(row * width + col).a);
3144 writePNG(filename.str(), width, height, pixel_data);
3148 return texture_filenames;
3151void Context::out_of_memory_handler() {
3152 helios_runtime_error(
"ERROR: Out of host memory. The program has run out of memory and cannot continue.");
3155void Context::install_out_of_memory_handler() {
3156 std::set_new_handler(out_of_memory_handler);
3160 for (
auto &[UUID, primitive]: primitives) {
3161 delete getPrimitivePointer_private(UUID);
3164 for (
auto &[UUID,
object]: objects) {
3165 delete getObjectPointer_private(UUID);
3172 helios_runtime_error(
"ERROR (Context::getPrimitiveType): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3175 return getPrimitivePointer_private(UUID)->getType();
3181 helios_runtime_error(
"ERROR (Context::setPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3185 uint current_objID = getPrimitivePointer_private(UUID)->getParentObjectID();
3186 getPrimitivePointer_private(UUID)->setParentObjectID(objID);
3188 if (current_objID != 0u && current_objID != objID) {
3190 objects.at(current_objID)->deleteChildPrimitive(UUID);
3192 if (getObjectPointer_private(current_objID)->getPrimitiveUUIDs().empty()) {
3195 objects.erase(current_objID);
3202 for (
uint UUID: UUIDs) {
3210 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3213 return getPrimitivePointer_private(UUID)->getParentObjectID();
3217 std::vector<uint> objIDs(UUIDs.size());
3218 for (
uint i = 0; i < UUIDs.size(); i++) {
3221 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUIDs[i]) +
" does not exist in the Context.");
3224 objIDs[i] = getPrimitivePointer_private(UUIDs[i])->getParentObjectID();
3236 std::vector<uint> primitiveObjIDs;
3237 if (UUIDs.empty()) {
3238 return primitiveObjIDs;
3242 primitiveObjIDs.resize(UUIDs.size());
3243 for (
uint i = 0; i < UUIDs.size(); i++) {
3246 helios_runtime_error(
"ERROR (Context::getUniquePrimitiveParentObjectIDs): Primitive with UUID of " + std::to_string(UUIDs.at(i)) +
" does not exist in the Context.");
3249 primitiveObjIDs.at(i) = getPrimitivePointer_private(UUIDs.at(i))->getParentObjectID();
3253 std::sort(primitiveObjIDs.begin(), primitiveObjIDs.end());
3256 auto it = unique(primitiveObjIDs.begin(), primitiveObjIDs.end());
3257 primitiveObjIDs.resize(distance(primitiveObjIDs.begin(), it));
3260 if (include_ObjID_zero ==
false & primitiveObjIDs.front() ==
uint(0)) {
3261 primitiveObjIDs.erase(primitiveObjIDs.begin());
3264 return primitiveObjIDs;
3270 helios_runtime_error(
"ERROR (Context::getPrimitiveArea): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3273 return getPrimitivePointer_private(UUID)->getArea();
3277 const std::vector UUIDs = {UUID};
3283 for (
uint UUID: UUIDs) {
3285 helios_runtime_error(
"ERROR (Context::getPrimitiveBoundingBox): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3291 min_corner = vertices.front();
3292 max_corner = min_corner;
3295 for (
const vec3 &vert: vertices) {
3296 if (vert.x < min_corner.
x) {
3297 min_corner.
x = vert.x;
3299 if (vert.y < min_corner.
y) {
3300 min_corner.
y = vert.y;
3302 if (vert.z < min_corner.
z) {
3303 min_corner.
z = vert.z;
3305 if (vert.x > max_corner.
x) {
3306 max_corner.
x = vert.x;
3308 if (vert.y > max_corner.
y) {
3309 max_corner.
y = vert.y;
3311 if (vert.z > max_corner.
z) {
3312 max_corner.
z = vert.z;
3321 return getPrimitivePointer_private(UUID)->getNormal();
3325 getPrimitivePointer_private(UUID)->getTransformationMatrix(T);
3329 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3333 for (
uint UUID: UUIDs) {
3334 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3339 return getPrimitivePointer_private(UUID)->getVertices();
3344 return getPrimitivePointer_private(UUID)->getColor();
3348 return getPrimitivePointer_private(UUID)->getColorRGB();
3352 return getPrimitivePointer_private(UUID)->getColorRGBA();
3356 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3357 getPrimitivePointer_private(UUID)->setColor(color);
3361 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3362 for (
uint UUID: UUIDs) {
3363 getPrimitivePointer_private(UUID)->setColor(color);
3368 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3369 getPrimitivePointer_private(UUID)->setColor(color);
3373 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3374 for (
uint UUID: UUIDs) {
3375 getPrimitivePointer_private(UUID)->setColor(color);
3380 return getPrimitivePointer_private(UUID)->getTextureFile();
3384 api_warnings.
addWarning(
"setPrimitiveTextureFile_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3385 getPrimitivePointer_private(UUID)->setTextureFile(texturefile.c_str());
3389 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3390 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3391 return textures.at(texturefile).getImageResolution();
3397 return getPrimitivePointer_private(UUID)->getTextureUV();
3401 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3402 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3403 return textures.at(texturefile).hasTransparencyChannel();
3410 const std::vector<std::vector<bool>> *data = textures.at(getPrimitivePointer_private(UUID)->getTextureFile()).getTransparencyData();
3414 helios_runtime_error(
"ERROR (Context::getPrimitiveTransparencyData): Texture transparency data does not exist for primitive " + std::to_string(UUID) +
".");
3419 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3420 getPrimitivePointer_private(UUID)->overrideTextureColor();
3424 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3425 for (
uint UUID: UUIDs) {
3426 getPrimitivePointer_private(UUID)->overrideTextureColor();
3431 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3432 getPrimitivePointer_private(UUID)->useTextureColor();
3436 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3437 for (
uint UUID: UUIDs) {
3438 getPrimitivePointer_private(UUID)->useTextureColor();
3443 return getPrimitivePointer_private(UUID)->isTextureColorOverridden();
3447 return getPrimitivePointer_private(UUID)->getSolidFraction();
3451 std::cout <<
"-------------------------------------------" << std::endl;
3452 std::cout <<
"Info for UUID " << UUID << std::endl;
3453 std::cout <<
"-------------------------------------------" << std::endl;
3458 stype =
"PRIMITIVE_TYPE_PATCH";
3459 }
else if (type == 1) {
3460 stype =
"PRIMITIVE_TYPE_TRIANGLE";
3461 }
else if (type == 2) {
3462 stype =
"PRIMITIVE_TYPE_VOXEL";
3465 std::cout <<
"Type: " << stype << std::endl;
3471 std::cout <<
"Patch Center: " <<
getPatchCenter(UUID) << std::endl;
3472 std::cout <<
"Patch Size: " <<
getPatchSize(UUID) << std::endl;
3474 std::cout <<
"Voxel Center: " <<
getVoxelCenter(UUID) << std::endl;
3475 std::cout <<
"Voxel Size: " <<
getVoxelSize(UUID) << std::endl;
3479 std::cout <<
"Vertices: " << std::endl;
3480 for (
uint i = 0; i < primitive_vertices.size(); i++) {
3481 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
3486 std::cout <<
"Transform: " << std::endl;
3487 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
3488 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
3489 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
3490 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
3495 std::cout <<
"Texture UV: " << std::endl;
3497 for (
uint i = 0; i < uv.size(); i++) {
3498 std::cout <<
" " << uv.at(i) << std::endl;
3506 std::cout <<
"Primitive Data: " << std::endl;
3509 for (
uint i = 0; i < pd.size(); i++) {
3515 dstype =
"HELIOS_TYPE_INT";
3517 dstype =
"HELIOS_TYPE_UINT";
3519 dstype =
"HELIOS_TYPE_FLOAT";
3521 dstype =
"HELIOS_TYPE_DOUBLE";
3523 dstype =
"HELIOS_TYPE_VEC2";
3525 dstype =
"HELIOS_TYPE_VEC3";
3527 dstype =
"HELIOS_TYPE_VEC4";
3529 dstype =
"HELIOS_TYPE_INT2";
3531 dstype =
"HELIOS_TYPE_INT3";
3533 dstype =
"HELIOS_TYPE_INT4";
3535 dstype =
"HELIOS_TYPE_STRING";
3541 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
3545 std::vector<int> pdata;
3547 for (
uint j = 0; j < dsize; j++) {
3549 std::cout <<
" " << pdata.at(j) << std::endl;
3551 std::cout <<
" ..." << std::endl;
3552 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3553 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3558 std::vector<uint> pdata;
3560 for (
uint j = 0; j < dsize; j++) {
3562 std::cout <<
" " << pdata.at(j) << std::endl;
3564 std::cout <<
" ..." << std::endl;
3565 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3566 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3571 std::vector<float> pdata;
3573 for (
uint j = 0; j < dsize; j++) {
3575 std::cout <<
" " << pdata.at(j) << std::endl;
3577 std::cout <<
" ..." << std::endl;
3578 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3579 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3584 std::vector<double> pdata;
3586 for (
uint j = 0; j < dsize; j++) {
3588 std::cout <<
" " << pdata.at(j) << std::endl;
3590 std::cout <<
" ..." << std::endl;
3591 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3592 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3597 std::vector<vec2> pdata;
3599 for (
uint j = 0; j < dsize; j++) {
3601 std::cout <<
" " << pdata.at(j) << std::endl;
3603 std::cout <<
" ..." << std::endl;
3604 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3605 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3610 std::vector<vec3> pdata;
3612 for (
uint j = 0; j < dsize; j++) {
3614 std::cout <<
" " << pdata.at(j) << std::endl;
3616 std::cout <<
" ..." << std::endl;
3617 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3618 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3623 std::vector<vec4> pdata;
3625 for (
uint j = 0; j < dsize; j++) {
3627 std::cout <<
" " << pdata.at(j) << std::endl;
3629 std::cout <<
" ..." << std::endl;
3630 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3631 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3636 std::vector<int2> pdata;
3638 for (
uint j = 0; j < dsize; j++) {
3640 std::cout <<
" " << pdata.at(j) << std::endl;
3642 std::cout <<
" ..." << std::endl;
3643 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3644 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3649 std::vector<int3> pdata;
3651 for (
uint j = 0; j < dsize; j++) {
3653 std::cout <<
" " << pdata.at(j) << std::endl;
3655 std::cout <<
" ..." << std::endl;
3656 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3657 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3662 std::vector<int4> pdata;
3664 for (
uint j = 0; j < dsize; j++) {
3666 std::cout <<
" " << pdata.at(j) << std::endl;
3668 std::cout <<
" ..." << std::endl;
3669 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3670 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3675 std::vector<std::string> pdata;
3677 for (
uint j = 0; j < dsize; j++) {
3679 std::cout <<
" " << pdata.at(j) << std::endl;
3681 std::cout <<
" ..." << std::endl;
3682 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3683 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3691 std::cout <<
"-------------------------------------------" << std::endl;
3697 auto it = material_label_to_id.find(material_label);
3698 if (it == material_label_to_id.end()) {
3699 helios_runtime_error(
"ERROR (Context::getMaterialIDFromLabel): Material with label '" + material_label +
"' does not exist.");
3705 if (material_label.empty()) {
3710 if (material_label.substr(0, 2) ==
"__" && material_label != DEFAULT_MATERIAL_LABEL) {
3711 helios_runtime_error(
"ERROR (Context::addMaterial): Material labels starting with '__' are reserved for internal use.");
3715 if (material_label_to_id.find(material_label) != material_label_to_id.end()) {
3716 std::cerr <<
"WARNING (Context::addMaterial): Material with label '" << material_label <<
"' already exists. Overwriting." << std::endl;
3718 uint oldID = material_label_to_id[material_label];
3719 materials.erase(oldID);
3723 uint newID = currentMaterialID++;
3725 materials[newID] = newMaterial;
3726 material_label_to_id[material_label] = newID;
3729uint Context::addMaterial_internal(
const std::string &label,
const RGBAcolor &color,
const std::string &texture) {
3731 if (label.empty()) {
3732 helios_runtime_error(
"ERROR (Context::addMaterial_internal): Material label cannot be empty.");
3736 if (material_label_to_id.find(label) != material_label_to_id.end()) {
3737 uint oldID = material_label_to_id[label];
3738 materials.erase(oldID);
3742 uint newID = currentMaterialID++;
3743 Material newMaterial(newID, label, color, texture,
false);
3744 materials[newID] = newMaterial;
3745 material_label_to_id[label] = newID;
3749std::string Context::generateMaterialLabel(
const RGBAcolor &color,
const std::string &texture,
bool texture_override)
const {
3752 hash ^= std::hash<float>{}(color.
r) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3753 hash ^= std::hash<float>{}(color.
g) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3754 hash ^= std::hash<float>{}(color.
b) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3755 hash ^= std::hash<float>{}(color.
a) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3756 hash ^= std::hash<std::string>{}(texture) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3757 hash ^= std::hash<bool>{}(texture_override) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3758 return "__auto_" + std::to_string(hash);
3761bool Context::isMaterialShared(
uint materialID)
const {
3762 if (materials.find(materialID) == materials.end()) {
3766 return materials.at(materialID).reference_count > 1;
3769uint Context::copyMaterialForPrimitive(
uint primitiveUUID) {
3770 Primitive *prim = getPrimitivePointer_private(primitiveUUID);
3771 uint oldMaterialID = prim->materialID;
3772 const Material &oldMaterial = materials.at(oldMaterialID);
3775 std::string newLabel =
"__copy_" + std::to_string(currentMaterialID) +
"_" + std::to_string(primitiveUUID);
3782 materials[newMaterialID].twosided_flag = oldMaterial.
twosided_flag;
3800 materials[oldMaterialID].reference_count--;
3801 materials[newMaterialID].reference_count = 1;
3804 prim->materialID = newMaterialID;
3806 return newMaterialID;
3810 if (material_label_to_id.find(old_label) == material_label_to_id.end()) {
3811 helios_runtime_error(
"ERROR (Context::renameMaterial): Material with label '" + old_label +
"' does not exist.");
3813 if (new_label.empty()) {
3816 if (new_label.substr(0, 2) ==
"__") {
3817 helios_runtime_error(
"ERROR (Context::renameMaterial): Material labels starting with '__' are reserved for internal use.");
3819 if (material_label_to_id.find(new_label) != material_label_to_id.end()) {
3820 helios_runtime_error(
"ERROR (Context::renameMaterial): Material with label '" + new_label +
"' already exists.");
3823 uint materialID = material_label_to_id.at(old_label);
3824 materials.at(materialID).label = new_label;
3827 if (old_label.substr(0, 7) !=
"__auto_") {
3828 material_label_to_id.erase(old_label);
3830 material_label_to_id[new_label] = materialID;
3834 return material_label_to_id.find(material_label) != material_label_to_id.end();
3838 std::vector<std::string> labels;
3839 labels.reserve(material_label_to_id.size());
3840 for (
const auto &pair: material_label_to_id) {
3842 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
3843 labels.push_back(pair.first);
3851 return materials.at(matID).color;
3856 return materials.at(matID).texture_file;
3861 return materials.at(matID).texture_color_overridden;
3866 materials[matID].color = color;
3872 if (!texture_file.empty()) {
3873 addTexture(texture_file.c_str());
3875 materials[matID].texture_file = texture_file;
3880 materials[matID].texture_color_overridden =
override;
3885 return materials.at(matID).twosided_flag;
3890 materials[matID].twosided_flag = twosided_flag;
3895 bool has_user_material = (mat_label.substr(0, 7) !=
"__auto_" && mat_label != DEFAULT_MATERIAL_LABEL);
3897 if (has_user_material) {
3907 return default_value;
3912 Primitive *prim = getPrimitivePointer_private(UUID);
3913 uint oldMaterialID = prim->materialID;
3915 materials[oldMaterialID].reference_count--;
3916 materials[materialID].reference_count++;
3917 prim->materialID = materialID;
3922 for (
uint UUID: UUIDs) {
3923 Primitive *prim = getPrimitivePointer_private(UUID);
3924 uint oldMaterialID = prim->materialID;
3926 materials[oldMaterialID].reference_count--;
3927 materials[materialID].reference_count++;
3928 prim->materialID = materialID;
3938 for (
uint ObjID: ObjIDs) {
3944 Primitive *prim = getPrimitivePointer_private(UUID);
3945 uint materialID = prim->materialID;
3947 if (materials.find(materialID) != materials.end()) {
3948 return materials.at(materialID).label;
3950 return DEFAULT_MATERIAL_LABEL;
3955 std::vector<uint> result;
3956 for (
const auto &pair: primitives) {
3957 if (pair.second->materialID == materialID) {
3958 result.push_back(pair.first);
3965 if (material_label == DEFAULT_MATERIAL_LABEL) {
3969 auto it = material_label_to_id.find(material_label);
3970 if (it == material_label_to_id.end()) {
3971 helios_runtime_error(
"ERROR (Context::deleteMaterial): Material with label '" + material_label +
"' does not exist.");
3974 uint materialID = it->second;
3978 if (!users.empty()) {
3979 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;
3981 for (
uint UUID: users) {
3982 Primitive *prim = getPrimitivePointer_private(UUID);
3984 materials[materialID].reference_count--;
3985 prim->materialID = 0;
3986 materials[0].reference_count++;
3991 materials.erase(materialID);
3992 material_label_to_id.erase(material_label);
3997 return materials.at(matID).doesMaterialDataExist(data_label);
4002 return materials.at(matID).getMaterialDataType(data_label);
4007 materials[matID].clearMaterialData(data_label);
4011 Primitive *prim = getPrimitivePointer_private(UUID);
4012 return prim->materialID;
4016 if (materials.find(materialID) == materials.end()) {
4017 helios_runtime_error(
"ERROR (Context::getMaterial): Material ID " + std::to_string(materialID) +
" does not exist.");
4019 return materials.at(materialID);
4025 for (
const auto &pair: material_label_to_id) {
4027 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
4035 std::cout <<
"-------------------------------------------" << std::endl;
4036 std::cout <<
"Info for ObjID " << ObjID << std::endl;
4037 std::cout <<
"-------------------------------------------" << std::endl;
4042 ostype =
"OBJECT_TYPE_TILE";
4043 }
else if (otype == 1) {
4044 ostype =
"OBJECT_TYPE_SPHERE";
4045 }
else if (otype == 2) {
4046 ostype =
"OBJECT_TYPE_TUBE";
4047 }
else if (otype == 3) {
4048 ostype =
"OBJECT_TYPE_BOX";
4049 }
else if (otype == 4) {
4050 ostype =
"OBJECT_TYPE_DISK";
4051 }
else if (otype == 5) {
4052 ostype =
"OBJECT_TYPE_POLYMESH";
4053 }
else if (otype == 6) {
4054 ostype =
"OBJECT_TYPE_CONE";
4057 std::cout <<
"Type: " << ostype << std::endl;
4058 std::cout <<
"Object Bounding Box Center: " <<
getObjectCenter(ObjID) << std::endl;
4059 std::cout <<
"One-sided Surface Area: " <<
getObjectArea(ObjID) << std::endl;
4064 std::cout <<
"Object Primitives Complete" << std::endl;
4066 std::cout <<
"Object Primitives Incomplete" << std::endl;
4069 std::cout <<
"Primitive UUIDs: " << std::endl;
4071 for (
uint i = 0; i < primitive_UUIDs.size(); i++) {
4076 pstype =
"PRIMITIVE_TYPE_PATCH";
4077 }
else if (ptype == 1) {
4078 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4080 std::cout <<
" " << primitive_UUIDs.at(i) <<
" (" << pstype <<
")" << std::endl;
4082 std::cout <<
" ..." << std::endl;
4086 pstype =
"PRIMITIVE_TYPE_PATCH";
4087 }
else if (ptype == 1) {
4088 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4090 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 2) <<
" (" << pstype <<
")" << std::endl;
4093 pstype =
"PRIMITIVE_TYPE_PATCH";
4094 }
else if (ptype == 1) {
4095 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4097 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 1) <<
" (" << pstype <<
")" << std::endl;
4108 std::cout <<
"Tile Texture UV: " << std::endl;
4110 for (
uint i = 0; i < uv.size(); i++) {
4111 std::cout <<
" " << uv.at(i) << std::endl;
4114 std::cout <<
"Tile Vertices: " << std::endl;
4116 for (
uint i = 0; i < primitive_vertices.size(); i++) {
4117 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
4125 std::cout <<
"Tube Nodes: " << std::endl;
4127 for (
uint i = 0; i < nodes.size(); i++) {
4129 std::cout <<
" " << nodes.at(i) << std::endl;
4131 std::cout <<
" ..." << std::endl;
4132 std::cout <<
" " << nodes.at(nodes.size() - 2) << std::endl;
4133 std::cout <<
" " << nodes.at(nodes.size() - 1) << std::endl;
4137 std::cout <<
"Tube Node Radii: " << std::endl;
4139 for (
uint i = 0; i < noderadii.size(); i++) {
4141 std::cout <<
" " << noderadii.at(i) << std::endl;
4143 std::cout <<
" ..." << std::endl;
4144 std::cout <<
" " << noderadii.at(noderadii.size() - 2) << std::endl;
4145 std::cout <<
" " << noderadii.at(noderadii.size() - 1) << std::endl;
4149 std::cout <<
"Tube Node Colors: " << std::endl;
4151 for (
uint i = 0; i < nodecolors.size(); i++) {
4153 std::cout <<
" " << nodecolors.at(i) << std::endl;
4155 std::cout <<
" ..." << std::endl;
4156 std::cout <<
" " << nodecolors.at(nodecolors.size() - 2) << std::endl;
4157 std::cout <<
" " << nodecolors.at(nodecolors.size() - 1) << std::endl;
4176 std::cout <<
"Cone Nodes: " << std::endl;
4178 for (
uint i = 0; i < nodes.size(); i++) {
4179 std::cout <<
" " << nodes.at(i) << std::endl;
4181 std::cout <<
"Cone Node Radii: " << std::endl;
4183 for (
uint i = 0; i < noderadii.size(); i++) {
4184 std::cout <<
" " << noderadii.at(i) << std::endl;
4191 std::cout <<
"Transform: " << std::endl;
4192 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
4193 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
4194 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
4195 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
4199 std::cout <<
"Object Data: " << std::endl;
4202 for (
uint i = 0; i < pd.size(); i++) {
4208 dstype =
"HELIOS_TYPE_INT";
4210 dstype =
"HELIOS_TYPE_UINT";
4212 dstype =
"HELIOS_TYPE_FLOAT";
4214 dstype =
"HELIOS_TYPE_DOUBLE";
4216 dstype =
"HELIOS_TYPE_VEC2";
4218 dstype =
"HELIOS_TYPE_VEC3";
4220 dstype =
"HELIOS_TYPE_VEC4";
4222 dstype =
"HELIOS_TYPE_INT2";
4224 dstype =
"HELIOS_TYPE_INT3";
4226 dstype =
"HELIOS_TYPE_INT4";
4228 dstype =
"HELIOS_TYPE_STRING";
4234 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
4238 std::vector<int> pdata;
4240 for (
uint j = 0; j < dsize; j++) {
4242 std::cout <<
" " << pdata.at(j) << std::endl;
4244 std::cout <<
" ..." << std::endl;
4245 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4246 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4251 std::vector<uint> pdata;
4253 for (
uint j = 0; j < dsize; j++) {
4255 std::cout <<
" " << pdata.at(j) << std::endl;
4257 std::cout <<
" ..." << std::endl;
4258 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4259 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4264 std::vector<float> pdata;
4266 for (
uint j = 0; j < dsize; j++) {
4268 std::cout <<
" " << pdata.at(j) << std::endl;
4270 std::cout <<
" ..." << std::endl;
4271 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4272 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4277 std::vector<double> pdata;
4279 for (
uint j = 0; j < dsize; j++) {
4281 std::cout <<
" " << pdata.at(j) << std::endl;
4283 std::cout <<
" ..." << std::endl;
4284 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4285 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4290 std::vector<vec2> pdata;
4292 for (
uint j = 0; j < dsize; j++) {
4294 std::cout <<
" " << pdata.at(j) << std::endl;
4296 std::cout <<
" ..." << std::endl;
4297 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4298 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4303 std::vector<vec3> pdata;
4305 for (
uint j = 0; j < dsize; j++) {
4307 std::cout <<
" " << pdata.at(j) << std::endl;
4309 std::cout <<
" ..." << std::endl;
4310 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4311 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4316 std::vector<vec4> pdata;
4318 for (
uint j = 0; j < dsize; j++) {
4320 std::cout <<
" " << pdata.at(j) << std::endl;
4322 std::cout <<
" ..." << std::endl;
4323 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4324 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4329 std::vector<int2> pdata;
4331 for (
uint j = 0; j < dsize; j++) {
4333 std::cout <<
" " << pdata.at(j) << std::endl;
4335 std::cout <<
" ..." << std::endl;
4336 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4337 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4342 std::vector<int3> pdata;
4344 for (
uint j = 0; j < dsize; j++) {
4346 std::cout <<
" " << pdata.at(j) << std::endl;
4348 std::cout <<
" ..." << std::endl;
4349 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4350 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4355 std::vector<int4> pdata;
4357 for (
uint j = 0; j < dsize; j++) {
4359 std::cout <<
" " << pdata.at(j) << std::endl;
4361 std::cout <<
" ..." << std::endl;
4366 std::vector<std::string> pdata;
4368 for (
uint j = 0; j < dsize; j++) {
4370 std::cout <<
" " << pdata.at(j) << std::endl;
4372 std::cout <<
" ..." << std::endl;
4380 std::cout <<
"-------------------------------------------" << std::endl;
4385 if (objects.find(ObjID) == objects.end()) {
4386 helios_runtime_error(
"ERROR (Context::getObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4389 return objects.at(ObjID);
4395 helios_runtime_error(
"ERROR (Context::hideObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4398 objects.at(ObjID)->ishidden =
true;
4399 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4402 helios_runtime_error(
"ERROR (Context::hideObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4405 primitives.at(UUID)->ishidden =
true;
4410 for (
uint ObjID: ObjIDs) {
4418 helios_runtime_error(
"ERROR (Context::showObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4421 objects.at(ObjID)->ishidden =
false;
4422 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4425 helios_runtime_error(
"ERROR (Context::showObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4428 primitives.at(UUID)->ishidden =
false;
4433 for (
uint ObjID: ObjIDs) {
4440 helios_runtime_error(
"ERROR (Context::isObjectHidden): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4442 return objects.at(ObjID)->ishidden;
4446 return getObjectPointer_private(ObjID)->
getArea();
4451 if (objects.find(ObjID) == objects.end()) {
4452 helios_runtime_error(
"ERROR (Context::getObjectAverageNormal): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4456 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4459 for (
uint UUID: UUIDs) {
4488 for (
uint ObjID: ObjIDs) {
4502 vec3 newN = normalize(new_normal);
4505 float d = std::clamp(oldN * newN, -1.f, 1.f);
4506 float angle = acosf(d);
4510 axis = (std::abs(oldN.
x) < std::abs(oldN.
z)) ?
cross(oldN, {1, 0, 0}) :
cross(oldN, {0, 0, 1});
4522 vec3 localX{1, 0, 0};
4529 vec3 worldX{1, 0, 0};
4530 vec3 targ = worldX - newN * (newN * worldX);
4531 targ = normalize(targ);
4534 float twist = atan2f(newN *
cross(t1, targ),
4548 objects.at(ObjID)->object_origin = origin;
4552 return getObjectPointer_private(ObjID)->
hasTexture();
4556 getObjectPointer_private(ObjID)->
setColor(color);
4560 for (
const uint ObjID: ObjIDs) {
4561 getObjectPointer_private(ObjID)->
setColor(color);
4566 getObjectPointer_private(ObjID)->
setColor(color);
4570 for (
const uint ObjID: ObjIDs) {
4571 getObjectPointer_private(ObjID)->
setColor(color);
4584 for (
uint ObjID: ObjIDs) {
4594 for (
uint ObjID: ObjIDs) {
4600 const std::vector ObjIDs{ObjID};
4606 for (
uint ObjID: ObjIDs) {
4607 if (objects.find(ObjID) == objects.end()) {
4608 helios_runtime_error(
"ERROR (Context::getObjectBoundingBox): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4611 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4614 for (
const uint UUID: UUIDs) {
4617 if (p == 0 && o == 0) {
4618 min_corner = vertices.front();
4619 max_corner = min_corner;
4624 for (
const vec3 &vert: vertices) {
4625 if (vert.x < min_corner.
x) {
4626 min_corner.
x = vert.x;
4628 if (vert.y < min_corner.
y) {
4629 min_corner.
y = vert.y;
4631 if (vert.z < min_corner.
z) {
4632 min_corner.
z = vert.z;
4634 if (vert.x > max_corner.
x) {
4635 max_corner.
x = vert.x;
4637 if (vert.y > max_corner.
y) {
4638 max_corner.
y = vert.y;
4640 if (vert.z > max_corner.
z) {
4641 max_corner.
z = vert.z;
4650Tile *Context::getTileObjectPointer_private(
uint ObjID)
const {
4652 if (objects.find(ObjID) == objects.end()) {
4653 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4654 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TILE) {
4655 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tile Object.");
4658 return dynamic_cast<Tile *
>(objects.at(ObjID));
4661Sphere *Context::getSphereObjectPointer_private(
uint ObjID)
const {
4663 if (objects.find(ObjID) == objects.end()) {
4664 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4665 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_SPHERE) {
4666 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Sphere Object.");
4669 return dynamic_cast<Sphere *
>(objects.at(ObjID));
4672Tube *Context::getTubeObjectPointer_private(
uint ObjID)
const {
4674 if (objects.find(ObjID) == objects.end()) {
4675 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4676 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TUBE) {
4677 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tube Object.");
4680 return dynamic_cast<Tube *
>(objects.at(ObjID));
4683Box *Context::getBoxObjectPointer_private(
uint ObjID)
const {
4685 if (objects.find(ObjID) == objects.end()) {
4686 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4687 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_BOX) {
4688 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Box Object.");
4691 return dynamic_cast<Box *
>(objects.at(ObjID));
4694Disk *Context::getDiskObjectPointer_private(
uint ObjID)
const {
4696 if (objects.find(ObjID) == objects.end()) {
4697 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4698 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_DISK) {
4699 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Disk Object.");
4702 return dynamic_cast<Disk *
>(objects.at(ObjID));
4705Polymesh *Context::getPolymeshObjectPointer_private(
uint ObjID)
const {
4707 if (objects.find(ObjID) == objects.end()) {
4708 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4709 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_POLYMESH) {
4710 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Polymesh Object.");
4713 return dynamic_cast<Polymesh *
>(objects.at(ObjID));
4716Cone *Context::getConeObjectPointer_private(
uint ObjID)
const {
4718 if (objects.find(ObjID) == objects.end()) {
4719 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4720 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_CONE) {
4721 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Cone Object.");
4724 return dynamic_cast<Cone *
>(objects.at(ObjID));
4728 return getTileObjectPointer_private(ObjID)->
getCenter();
4732 return getTileObjectPointer_private(ObjID)->
getSize();
4740 return getTileObjectPointer_private(ObjID)->
getNormal();
4744 return getTileObjectPointer_private(ObjID)->
getTextureUV();
4748 return getTileObjectPointer_private(ObjID)->
getVertices();
4752 return getSphereObjectPointer_private(ObjID)->
getCenter();
4756 return getSphereObjectPointer_private(ObjID)->
getRadius();
4764 return getSphereObjectPointer_private(ObjID)->
getVolume();
4772 return getTubeObjectPointer_private(ObjID)->
getNodes();
4776 return getTubeObjectPointer_private(ObjID)->
getNodeCount();
4780 return getTubeObjectPointer_private(ObjID)->
getNodeRadii();
4784 return getTubeObjectPointer_private(ObjID)->
getNodeColors();
4788 return getTubeObjectPointer_private(ObjID)->
getVolume();
4792 return getTubeObjectPointer_private(ObjID)->
getSegmentVolume(segment_index);
4797 if (objects.find(ObjID) == objects.end()) {
4798 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4806 if (objects.find(ObjID) == objects.end()) {
4807 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4810 dynamic_cast<Tube *
>(objects.at(ObjID))->
appendTubeSegment(node_position, node_radius, texturefile, textureuv_ufrac);
4815 if (objects.find(ObjID) == objects.end()) {
4816 helios_runtime_error(
"ERROR (Context::scaleTubeGirth): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4824 if (objects.find(ObjID) == objects.end()) {
4825 helios_runtime_error(
"ERROR (Context::setTubeRadii): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4833 if (objects.find(ObjID) == objects.end()) {
4834 helios_runtime_error(
"ERROR (Context::scaleTubeLength): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4842 if (objects.find(ObjID) == objects.end()) {
4843 helios_runtime_error(
"ERROR (Context::pruneTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4851 if (objects.find(ObjID) == objects.end()) {
4852 helios_runtime_error(
"ERROR (Context::setTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4859 return getBoxObjectPointer_private(ObjID)->
getCenter();
4863 return getBoxObjectPointer_private(ObjID)->
getSize();
4871 return getBoxObjectPointer_private(ObjID)->
getVolume();
4875 return getDiskObjectPointer_private(ObjID)->
getCenter();
4879 return getDiskObjectPointer_private(ObjID)->
getSize();
4895 return getConeObjectPointer_private(ObjID)->
getNodeRadii();
4903 return getConeObjectPointer_private(ObjID)->
getNodeRadius(number);
4911 return getConeObjectPointer_private(ObjID)->
getLength();
4915 return getConeObjectPointer_private(ObjID)->
getVolume();
4919 getConeObjectPointer_private(ObjID)->
scaleLength(scale_factor);
4923 getConeObjectPointer_private(ObjID)->
scaleGirth(scale_factor);
4927 return getPolymeshObjectPointer_private(ObjID)->
getVolume();
4931 api_warnings.
report(std::cerr);