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);
504 std::sort(cached_all_uuids.begin(), cached_all_uuids.end());
506 all_uuids_cache_valid =
true;
507 return cached_all_uuids;
512 size_t dirty_count = std::count_if(primitives.begin(), primitives.end(), [&](
auto const &kv) { return isPrimitiveDirty(kv.first); });
514 std::vector<uint> dirty_UUIDs;
515 dirty_UUIDs.reserve(dirty_count);
516 for (
const auto &[UUID, primitive]: primitives) {
517 if (!primitive->dirty_flag || primitive->ishidden) {
520 dirty_UUIDs.push_back(UUID);
523 if (include_deleted_UUIDs) {
524 dirty_UUIDs.insert(dirty_UUIDs.end(), dirty_deleted_primitives.begin(), dirty_deleted_primitives.end());
531 return dirty_deleted_primitives;
537 helios_runtime_error(
"ERROR (Context::hidePrimitive): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
540 primitives.at(UUID)->ishidden =
true;
541 invalidateAllUUIDsCache();
545 for (
uint UUID: UUIDs) {
553 helios_runtime_error(
"ERROR (Context::showPrimitive): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
556 primitives.at(UUID)->ishidden =
false;
557 invalidateAllUUIDsCache();
561 for (
uint UUID: UUIDs) {
568 helios_runtime_error(
"ERROR (Context::isPrimitiveHidden): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
570 return primitives.at(UUID)->ishidden;
574 for (
size_t i = UUIDs.size(); i-- > 0;) {
576 UUIDs.erase(UUIDs.begin() + i);
582 for (
auto &vec: UUIDs) {
583 for (
auto it = vec.begin(); it != vec.end();) {
594 for (
auto &vec2D: UUIDs) {
595 for (
auto &vec: vec2D) {
596 for (
auto it = vec.begin(); it != vec.end();) {
609 double date_value = floor(date.
year * 366.25) + date.
JulianDay();
610 date_value += double(time.
hour) / 24. + double(time.
minute) / 1440. + double(time.
second) / 86400.;
613 if (timeseries_data.find(label) == timeseries_data.end()) {
614 timeseries_data[label].push_back(value);
615 timeseries_datevalue[label].push_back(date_value);
621 auto it_data = timeseries_data[label].begin();
622 auto it_datevalue = timeseries_datevalue[label].begin();
625 if (date_value < timeseries_datevalue[label].front()) {
626 timeseries_data[label].insert(it_data, value);
627 timeseries_datevalue[label].insert(it_datevalue, date_value);
630 timeseries_data[label].insert(it_data + 1, value);
631 timeseries_datevalue[label].insert(it_datevalue + 1, date_value);
635 if (date_value < timeseries_datevalue[label].front()) {
636 timeseries_data[label].insert(it_data, value);
637 timeseries_datevalue[label].insert(it_datevalue, date_value);
639 }
else if (date_value > timeseries_datevalue[label].back()) {
640 timeseries_data[label].push_back(value);
641 timeseries_datevalue[label].push_back(date_value);
646 for (
uint t = 0; t < N - 1; t++) {
647 if (date_value == timeseries_datevalue[label].at(t)) {
648 std::cerr <<
"WARNING (Context::addTimeseriesData): Skipping duplicate timeseries date/time." << std::endl;
651 if (date_value > timeseries_datevalue[label].at(t) && date_value < timeseries_datevalue[label].at(t + 1)) {
652 timeseries_data[label].insert(it_data + t + 1, value);
653 timeseries_datevalue[label].insert(it_datevalue + t + 1, date_value);
660 helios_runtime_error(
"ERROR (Context::addTimeseriesData): Failed to insert timeseries data for unknown reason.");
664 if (timeseries_data.find(label) == timeseries_data.end()) {
665 helios_runtime_error(
"ERROR (setCurrentTimeseriesPoint): Timeseries variable `" + std::string(label) +
"' does not exist.");
672 if (timeseries_data.find(label) == timeseries_data.end()) {
673 helios_runtime_error(
"ERROR (setCurrentTimeseriesData): Timeseries variable `" + std::string(label) +
"' does not exist.");
676 double date_value = floor(date.
year * 366.25) + date.
JulianDay();
677 date_value += double(time.
hour) / 24. + double(time.
minute) / 1440. + double(time.
second) / 86400.;
679 double tmin = timeseries_datevalue.at(label).front();
680 double tmax = timeseries_datevalue.at(label).back();
682 if (date_value < tmin) {
683 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;
684 return timeseries_data.at(label).front();
685 }
else if (date_value > tmax) {
686 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;
687 return timeseries_data.at(label).back();
690 if (timeseries_datevalue.at(label).empty()) {
691 std::cerr <<
"WARNING (queryTimeseriesData): timeseries " << label <<
" does not contain any data." << std::endl;
693 }
else if (timeseries_datevalue.at(label).size() == 1) {
694 return timeseries_data.at(label).front();
697 bool success =
false;
698 for (i = 0; i < timeseries_data.at(label).size() - 1; i++) {
699 if (date_value >= timeseries_datevalue.at(label).at(i) && date_value <= timeseries_datevalue.at(label).at(i + 1)) {
706 helios_runtime_error(
"ERROR (queryTimeseriesData): Failed to query timeseries data for unknown reason.");
709 double xminus = timeseries_data.at(label).at(i);
710 double xplus = timeseries_data.at(label).at(i + 1);
712 double tminus = timeseries_datevalue.at(label).at(i);
713 double tplus = timeseries_datevalue.at(label).at(i + 1);
715 return float(xminus + (xplus - xminus) * (date_value - tminus) / (tplus - tminus));
724 if (timeseries_data.find(label) == timeseries_data.end()) {
725 helios_runtime_error(
"ERROR( Context::getTimeseriesData): Timeseries variable " + std::string(label) +
" does not exist.");
728 return timeseries_data.at(label).at(index);
732 if (timeseries_data.find(label) == timeseries_data.end()) {
733 helios_runtime_error(
"ERROR( Context::getTimeseriesTime): Timeseries variable " + std::string(label) +
" does not exist.");
736 double dateval = timeseries_datevalue.at(label).at(index);
738 int year = floor(floor(dateval) / 366.25);
739 assert(year > 1000 && year < 10000);
741 int JD = floor(dateval - floor(
double(year) * 366.25));
742 assert(JD > 0 && JD < 367);
744 int hour = floor((dateval - floor(dateval)) * 24.);
745 int minute = floor(((dateval - floor(dateval)) * 24. -
double(hour)) * 60.);
746 int second = (int) lround((((dateval - floor(dateval)) * 24. -
double(hour)) * 60. -
double(minute)) * 60.);
758 assert(second >= 0 && second < 60);
759 assert(minute >= 0 && minute < 60);
760 assert(hour >= 0 && hour < 24);
766 if (timeseries_data.find(label) == timeseries_data.end()) {
767 helios_runtime_error(
"ERROR( Context::getTimeseriesDate): Timeseries variable " + std::string(label) +
" does not exist.");
770 double dateval = timeseries_datevalue.at(label).at(index);
772 int year = floor(floor(dateval) / 366.25);
773 assert(year > 1000 && year < 10000);
775 int JD = floor(dateval - floor(
double(year) * 366.25));
776 assert(JD > 0 && JD < 367);
783 if (timeseries_data.find(label) == timeseries_data.end()) {
784 helios_runtime_error(
"ERROR (Context::getTimeseriesDate): Timeseries variable `" + std::string(label) +
"' does not exist.");
786 size = timeseries_data.at(label).size();
793 if (timeseries_data.find(label) == timeseries_data.end()) {
801 std::vector<std::string> labels;
802 labels.reserve(timeseries_data.size());
803 for (
const auto &[timeseries_label, timeseries_data]: timeseries_data) {
804 labels.push_back(timeseries_label);
828 float local_xmin = 1e8, local_xmax = -1e8;
829 float local_ymin = 1e8, local_ymax = -1e8;
830 float local_zmin = 1e8, local_zmax = -1e8;
833#pragma omp for nowait
834 for (
int i = 0; i < (int) UUIDs.size(); i++) {
836 const std::vector<vec3> &verts = getPrimitivePointer_private(UUIDs[i])->getVertices();
838 for (
const auto &vert: verts) {
839 local_xmin = std::min(local_xmin, vert.x);
840 local_xmax = std::max(local_xmax, vert.x);
841 local_ymin = std::min(local_ymin, vert.y);
842 local_ymax = std::max(local_ymax, vert.y);
843 local_zmin = std::min(local_zmin, vert.z);
844 local_zmax = std::max(local_zmax, vert.z);
851 xbounds.
x = std::min(xbounds.
x, local_xmin);
852 xbounds.
y = std::max(xbounds.
y, local_xmax);
853 ybounds.
x = std::min(ybounds.
x, local_ymin);
854 ybounds.
y = std::max(ybounds.
y, local_ymax);
855 zbounds.
x = std::min(zbounds.
x, local_zmin);
856 zbounds.
y = std::max(zbounds.
y, local_zmax);
862 for (
uint UUID: UUIDs) {
863 const std::vector<vec3> &verts = getPrimitivePointer_private(UUID)->getVertices();
865 for (
auto &vert: verts) {
866 if (vert.x < xbounds.
x) {
868 }
else if (vert.x > xbounds.
y) {
871 if (vert.y < ybounds.
x) {
873 }
else if (vert.y > ybounds.
y) {
876 if (vert.z < zbounds.
x) {
878 }
else if (vert.z > zbounds.
y) {
888 vec2 xbounds, ybounds, zbounds;
891 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
892 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
893 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
895 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
899 vec2 xbounds, ybounds, zbounds;
902 center.
x = xbounds.
x + 0.5f * (xbounds.
y - xbounds.
x);
903 center.
y = ybounds.
x + 0.5f * (ybounds.
y - ybounds.
x);
904 center.
z = zbounds.
x + 0.5f * (zbounds.
y - zbounds.
x);
906 radius = 0.5f * sqrtf(powf(xbounds.
y - xbounds.
x, 2) + powf(ybounds.
y - ybounds.
x, 2) + powf((zbounds.
y - zbounds.
x), 2));
910 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
912 for (
uint p: UUIDs_all) {
913 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
915 for (
auto &vertex: vertices) {
916 if (vertex.x < xbounds.
x || vertex.x > xbounds.
y) {
924 std::cerr <<
"WARNING (Context::cropDomainX): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
929 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
931 for (
uint p: UUIDs_all) {
932 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
934 for (
auto &vertex: vertices) {
935 if (vertex.y < ybounds.
x || vertex.y > ybounds.
y) {
943 std::cerr <<
"WARNING (Context::cropDomainY): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
948 const std::vector<uint> &UUIDs_all =
getAllUUIDs();
950 for (
uint p: UUIDs_all) {
951 const std::vector<vec3> &vertices = getPrimitivePointer_private(p)->getVertices();
953 for (
auto &vertex: vertices) {
954 if (vertex.z < zbounds.
x || vertex.z > zbounds.
y) {
962 std::cerr <<
"WARNING (Context::cropDomainZ): No primitives were inside cropped area, and thus all primitives were deleted." << std::endl;
967 size_t delete_count = 0;
968 for (
uint UUID: UUIDs) {
969 const std::vector<vec3> &vertices = getPrimitivePointer_private(UUID)->getVertices();
971 for (
auto &vertex: vertices) {
972 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) {
980 if (delete_count == UUIDs.size()) {
981 std::cerr <<
"WARNING (Context::cropDomain): No specified primitives were entirely inside cropped area, and thus all specified primitives were deleted." << std::endl;
996 helios_runtime_error(
"ERROR (Context::areObjectPrimitivesComplete): Object ID of " + std::to_string(objID) +
" does not exist in the context.");
1003 for (
auto it = objIDs.begin(); it != objIDs.end();) {
1005 it = objIDs.erase(it);
1013 for (
auto &vec: objIDs) {
1014 for (
auto it = vec.begin(); it != vec.end();) {
1025 for (
auto &vec2D: objIDs) {
1026 for (
auto &vec: vec2D) {
1027 for (
auto it = vec.begin(); it != vec.end();) {
1039 return objects.size();
1043 return objects.find(ObjID) != objects.end();
1047 std::vector<uint> objIDs;
1048 objIDs.reserve(objects.size());
1050 for (
auto [objID,
object]: objects) {
1054 objIDs.push_back(objID);
1061 for (
const uint ObjID: ObjIDs) {
1067 if (objects.find(ObjID) == objects.end()) {
1068 helios_runtime_error(
"ERROR (Context::deleteObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1073 for (
const auto &[label, type]:
obj->object_data_types) {
1074 decrementObjectDataLabelCounter(label);
1077 const std::vector<uint> &UUIDs =
obj->getPrimitiveUUIDs();
1081 objects.erase(ObjID);
1087 std::vector<uint> ObjIDs_copy(ObjIDs.size());
1089 for (
uint ObjID: ObjIDs) {
1098 if (objects.find(ObjID) == objects.end()) {
1099 helios_runtime_error(
"ERROR (Context::copyObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1102 ObjectType type = objects.at(ObjID)->getObjectType();
1104 const std::vector<uint> &UUIDs = getObjectPointer_private(ObjID)->
getPrimitiveUUIDs();
1107 for (
uint p: UUIDs_copy) {
1108 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1111 const std::string &texturefile = objects.at(ObjID)->getTextureFile();
1114 Tile *o = getTileObjectPointer_private(ObjID);
1118 auto *tile_new = (
new Tile(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1120 objects[currentObjectID] = tile_new;
1122 Sphere *o = getSphereObjectPointer_private(ObjID);
1126 auto *sphere_new = (
new Sphere(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1128 objects[currentObjectID] = sphere_new;
1130 Tube *o = getTubeObjectPointer_private(ObjID);
1132 const std::vector<vec3> &nodes = o->
getNodes();
1138 auto *tube_new = (
new Tube(currentObjectID, UUIDs_copy, nodes, radius, colors, triangle_vertices, subdiv, texturefile.c_str(),
this));
1140 objects[currentObjectID] = tube_new;
1142 Box *o = getBoxObjectPointer_private(ObjID);
1146 auto *box_new = (
new Box(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1148 objects[currentObjectID] = box_new;
1150 Disk *o = getDiskObjectPointer_private(ObjID);
1154 auto *disk_new = (
new Disk(currentObjectID, UUIDs_copy, subdiv, texturefile.c_str(),
this));
1156 objects[currentObjectID] = disk_new;
1158 auto *polymesh_new = (
new Polymesh(currentObjectID, UUIDs_copy, texturefile.c_str(),
this));
1160 objects[currentObjectID] = polymesh_new;
1162 Cone *o = getConeObjectPointer_private(ObjID);
1168 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));
1170 objects[currentObjectID] = cone_new;
1181 return currentObjectID - 1;
1185 std::vector<uint> output_object_IDs;
1186 output_object_IDs.resize(IDs.size());
1187 uint passed_count = 0;
1189 for (
uint i = 0; i < IDs.size(); i++) {
1195 if (strcmp(comparator,
"<") == 0) {
1196 if (
float(
R) < threshold) {
1197 output_object_IDs.at(passed_count) = IDs.at(i);
1200 }
else if (strcmp(comparator,
">") == 0) {
1201 if (
float(
R) > threshold) {
1202 output_object_IDs.at(passed_count) = IDs.at(i);
1205 }
else if (strcmp(comparator,
"=") == 0) {
1206 if (
float(
R) == threshold) {
1207 output_object_IDs.at(passed_count) = IDs.at(i);
1215 if (strcmp(comparator,
"<") == 0) {
1216 if (
R < threshold) {
1217 output_object_IDs.at(passed_count) = IDs.at(i);
1220 }
else if (strcmp(comparator,
">") == 0) {
1221 if (
R > threshold) {
1222 output_object_IDs.at(passed_count) = IDs.at(i);
1225 }
else if (strcmp(comparator,
"=") == 0) {
1226 if (
R == threshold) {
1227 output_object_IDs.at(passed_count) = IDs.at(i);
1235 if (strcmp(comparator,
"<") == 0) {
1236 if (
float(
R) < threshold) {
1237 output_object_IDs.at(passed_count) = IDs.at(i);
1240 }
else if (strcmp(comparator,
">") == 0) {
1241 if (
float(
R) > threshold) {
1242 output_object_IDs.at(passed_count) = IDs.at(i);
1245 }
else if (strcmp(comparator,
"=") == 0) {
1246 if (
float(
R) == threshold) {
1247 output_object_IDs.at(passed_count) = IDs.at(i);
1252 std::cerr <<
"WARNING: Object data not of type UINT, INT, or FLOAT. Filtering for other types not yet supported." << std::endl;
1257 output_object_IDs.resize(passed_count);
1259 return output_object_IDs;
1265 helios_runtime_error(
"ERROR (Context::translateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1268 getObjectPointer_private(ObjID)->
translate(shift);
1272 for (
uint ID: ObjIDs) {
1280 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1283 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_xyz);
1286void Context::rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const char *rotation_axis_xyz)
const {
1287 for (
uint ID: ObjIDs) {
1295 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1298 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_axis_vector);
1302 for (
uint ID: ObjIDs) {
1303 rotateObject(ID, rotation_radians, rotation_axis_vector);
1310 helios_runtime_error(
"ERROR (Context::rotateObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1313 getObjectPointer_private(ObjID)->
rotate(rotation_radians, rotation_origin, rotation_axis_vector);
1317 for (
uint ID: ObjIDs) {
1318 rotateObject(ID, rotation_radians, rotation_origin, rotation_axis_vector);
1325 helios_runtime_error(
"ERROR (Context::rotateObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1328 getObjectPointer_private(ObjID)->
rotate(rotation_radians, objects.at(ObjID)->object_origin, rotation_axis_vector);
1332 for (
uint ID: ObjIDs) {
1333 rotateObject(ID, rotation_radians, objects.at(ID)->object_origin, rotation_axis_vector);
1340 helios_runtime_error(
"ERROR (Context::scaleObject): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1343 getObjectPointer_private(ObjID)->
scale(scalefact);
1347 for (
uint ID: ObjIDs) {
1355 helios_runtime_error(
"ERROR (Context::scaleObjectAboutCenter): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1362 for (
uint ID: ObjIDs) {
1370 helios_runtime_error(
"ERROR (Context::scaleObjectAboutPoint): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1377 for (
uint ID: ObjIDs) {
1385 helios_runtime_error(
"ERROR (Context::scaleObjectAboutOrigin): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1388 getObjectPointer_private(ObjID)->
scaleAboutPoint(scalefact, objects.at(ObjID)->object_origin);
1392 for (
uint ID: ObjIDs) {
1400 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1406 std::vector<uint> UUIDs;
1410 UUIDs.push_back(UUID);
1420 std::vector<uint> output_UUIDs;
1422 for (
uint ObjID: ObjIDs) {
1425 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1429 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1431 return output_UUIDs;
1435 std::vector<uint> output_UUIDs;
1437 for (
uint j = 0; j < ObjIDs.size(); j++) {
1438 for (
uint i = 0; i < ObjIDs.at(j).size(); i++) {
1441 helios_runtime_error(
"ERROR (Context::getObjectPrimitiveUUIDs): Object ID of " + std::to_string(ObjIDs.at(j).at(i)) +
" not found in the context.");
1445 const std::vector<uint> ¤t_UUIDs = getObjectPointer_private(ObjIDs.at(j).at(i))->
getPrimitiveUUIDs();
1446 output_UUIDs.insert(output_UUIDs.end(), current_UUIDs.begin(), current_UUIDs.end());
1449 return output_UUIDs;
1458 helios_runtime_error(
"ERROR (Context::getObjectType): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1467 helios_runtime_error(
"ERROR (Context::getTileObjectAreaRatio): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1471 std::cerr <<
"WARNING (Context::getTileObjectAreaRatio): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1475 if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1476 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;
1480 if (subdiv.
x == 1 && subdiv.
y == 1) {
1484 float area = getTileObjectPointer_private(ObjID)->
getArea();
1485 const vec2 size = getTileObjectPointer_private(ObjID)->
getSize();
1487 float subpatch_area = size.
x * size.
y / scast<float>(subdiv.
x * subdiv.
y);
1488 return area / subpatch_area;
1492 std::vector<float> AreaRatios(ObjIDs.size());
1493 for (
uint i = 0; i < ObjIDs.size(); i++) {
1502 std::vector<uint> tile_ObjectIDs;
1503 std::vector<uint> textured_tile_ObjectIDs;
1506 std::vector<std::string> tex;
1508 for (
uint ObjID: ObjIDs) {
1511 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1517 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1518 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1519 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is missing primitives. Skipping..." << std::endl;
1522 Patch *p = getPatchPointer_private(getObjectPointer_private(ObjID)->getPrimitiveUUIDs().at(0));
1523 if (!p->hasTexture()) {
1524 tile_ObjectIDs.push_back(ObjID);
1526 textured_tile_ObjectIDs.push_back(ObjID);
1527 tex.push_back(p->getTextureFile());
1533 for (
unsigned int tile_ObjectID: tile_ObjectIDs) {
1534 Tile *current_object_pointer = getTileObjectPointer_private(tile_ObjectID);
1535 const std::vector<uint> &UUIDs_old = current_object_pointer->
getPrimitiveUUIDs();
1543 std::vector<uint> UUIDs_new =
addTile(center, size, rotation, new_subdiv, color);
1545 for (
uint UUID: UUIDs_new) {
1546 getPrimitivePointer_private(UUID)->setParentObjectID(tile_ObjectID);
1555 sort(tex.begin(), tex.end());
1556 std::vector<std::string>::iterator it;
1557 it = std::unique(tex.begin(), tex.end());
1558 tex.resize(std::distance(tex.begin(), it));
1561 std::vector<uint> object_templates;
1562 std::vector<std::vector<uint>> template_primitives;
1563 for (
uint j = 0; j < tex.size(); j++) {
1566 object_templates.emplace_back(object_template);
1567 std::vector<uint> object_primitives = getTileObjectPointer_private(object_template)->
getPrimitiveUUIDs();
1568 template_primitives.emplace_back(object_primitives);
1573 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1575 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1576 std::string current_texture_file = current_object_pointer->
getTextureFile();
1586 for (
uint j = 0; j < tex.size(); j++) {
1588 if (current_texture_file == tex.at(j)) {
1590 std::vector<uint> new_primitives =
copyPrimitive(template_primitives.at(j));
1613 current_object_pointer->
translate(center);
1625 std::vector<uint> tile_ObjectIDs;
1626 std::vector<uint> textured_tile_ObjectIDs;
1628 std::vector<std::string> tex;
1630 for (
uint ObjID: ObjIDs) {
1633 helios_runtime_error(
"ERROR (Context::setTileObjectSubdivisionCount): Object ID of " + std::to_string(ObjID) +
" not found in the context.");
1639 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is not a tile object. Skipping..." << std::endl;
1640 }
else if (!(getObjectPointer_private(ObjID)->arePrimitivesComplete())) {
1641 std::cerr <<
"WARNING (Context::setTileObjectSubdivisionCount): ObjectID " << ObjID <<
" is missing primitives. Skipping..." << std::endl;
1644 Patch *p = getPatchPointer_private(getObjectPointer_private(ObjID)->getPrimitiveUUIDs().at(0));
1645 if (!p->hasTexture()) {
1646 tile_ObjectIDs.push_back(ObjID);
1648 textured_tile_ObjectIDs.push_back(ObjID);
1649 tex.push_back(p->getTextureFile());
1655 for (
uint i = 0; i < tile_ObjectIDs.size(); i++) {
1656 Tile *current_object_pointer = getTileObjectPointer_private(tile_ObjectIDs.at(i));
1665 float tile_area = current_object_pointer->
getArea();
1668 float subpatch_dimension = sqrtf(tile_area / area_ratio);
1669 float subpatch_per_x = size.
x / subpatch_dimension;
1670 float subpatch_per_y = size.
y / subpatch_dimension;
1672 float option_1_AR = (tile_area / (size.
x / ceil(subpatch_per_x) * size.
y / floor(subpatch_per_y))) - area_ratio;
1673 float option_2_AR = (tile_area / (size.
x / floor(subpatch_per_x) * size.
y / ceil(subpatch_per_y))) - area_ratio;
1676 if ((
int) area_ratio == 1) {
1678 }
else if (option_1_AR >= option_2_AR) {
1679 new_subdiv =
make_int2(ceil(subpatch_per_x), floor(subpatch_per_y));
1681 new_subdiv =
make_int2(floor(subpatch_per_x), ceil(subpatch_per_y));
1685 std::vector<uint> UUIDs_new =
addTile(center, size, rotation, new_subdiv, color);
1687 for (
uint UUID: UUIDs_new) {
1688 getPrimitivePointer_private(UUID)->setParentObjectID(tile_ObjectIDs.at(i));
1697 sort(tex.begin(), tex.end());
1698 std::vector<std::string>::iterator it;
1699 it = std::unique(tex.begin(), tex.end());
1700 tex.resize(std::distance(tex.begin(), it));
1706 std::vector<uint> object_templates;
1707 std::vector<std::vector<uint>> template_primitives;
1708 for (
uint j = 0; j < tex.size(); j++) {
1711 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1713 Tile *current_object_pointer_b = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1714 std::string current_texture_file_b = current_object_pointer_b->
getTextureFile();
1716 if (current_texture_file_b == tex.at(j)) {
1723 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(ii));
1724 vec2 tile_size = current_object_pointer->
getSize();
1725 float tile_area = current_object_pointer->
getArea();
1728 float subpatch_dimension = sqrtf(tile_area / area_ratio);
1729 float subpatch_per_x = tile_size.
x / subpatch_dimension;
1730 float subpatch_per_y = tile_size.
y / subpatch_dimension;
1732 float option_1_AR = (tile_area / (tile_size.
x / ceil(subpatch_per_x) * tile_size.
y / floor(subpatch_per_y))) - area_ratio;
1733 float option_2_AR = (tile_area / (tile_size.
x / floor(subpatch_per_x) * tile_size.
y / ceil(subpatch_per_y))) - area_ratio;
1736 if ((
int) area_ratio == 1) {
1738 }
else if (option_1_AR >= option_2_AR) {
1739 new_subdiv =
make_int2(ceil(subpatch_per_x), floor(subpatch_per_y));
1741 new_subdiv =
make_int2(floor(subpatch_per_x), ceil(subpatch_per_y));
1746 object_templates.emplace_back(object_template);
1747 std::vector<uint> object_primitives = getTileObjectPointer_private(object_template)->
getPrimitiveUUIDs();
1748 template_primitives.emplace_back(object_primitives);
1753 for (
uint i = 0; i < textured_tile_ObjectIDs.size(); i++) {
1755 Tile *current_object_pointer = getTileObjectPointer_private(textured_tile_ObjectIDs.at(i));
1757 std::string current_texture_file = current_object_pointer->
getTextureFile();
1767 for (
uint j = 0; j < tex.size(); j++) {
1769 if (current_texture_file == tex.at(j)) {
1771 std::vector<uint> new_primitives =
copyPrimitive(template_primitives.at(j));
1795 current_object_pointer->
translate(center);
1808 return addSphere(Ndivs, center, radius, color);
1812 std::vector<uint> UUID;
1814 float dtheta =
PI_F / float(Ndivs);
1815 float dphi = 2.0f *
PI_F / float(Ndivs);
1818 for (
int j = 0; j < Ndivs; j++) {
1827 for (
int j = 0; j < Ndivs; j++) {
1836 for (
int j = 0; j < Ndivs; j++) {
1837 for (
int i = 1; i < Ndivs - 1; i++) {
1852 if (!validateTextureFileExtenstion(texturefile)) {
1853 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1854 }
else if (!doesTextureFileExist(texturefile)) {
1855 helios_runtime_error(
"ERROR (Context::addSphere): Texture file " + std::string(texturefile) +
" does not exist.");
1858 std::vector<uint> UUID;
1860 float dtheta =
PI_F / float(Ndivs);
1861 float dphi = 2.0f *
PI_F / float(Ndivs);
1864 for (
int j = 0; j < Ndivs; j++) {
1869 vec3 n0 = v0 - center;
1871 vec3 n1 = v1 - center;
1873 vec3 n2 = v2 - center;
1876 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);
1877 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);
1878 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);
1880 if (j == Ndivs - 1) {
1884 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1886 UUID.push_back(triangle_uuid);
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(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);
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++) {
1923 for (
int i = 1; i < Ndivs - 1; i++) {
1929 vec3 n0 = v0 - center;
1931 vec3 n1 = v1 - center;
1933 vec3 n2 = v2 - center;
1935 vec3 n3 = v3 - center;
1938 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);
1939 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);
1940 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);
1941 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);
1943 if (j == Ndivs - 1) {
1948 uint triangle_uuid1 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1950 UUID.push_back(triangle_uuid1);
1954 uint triangle_uuid2 =
addTriangle(v0, v2, v3, texturefile, uv0, uv2, uv3);
1956 UUID.push_back(triangle_uuid2);
1969 return addTile(center, size, rotation, subdiv, color);
1974 subsize.
x = size.
x / float(subdiv.
x);
1975 subsize.
y = size.
y / float(subdiv.
y);
1977 std::vector<uint> UUID(subdiv.
x * subdiv.
y);
1980 for (
uint j = 0; j < subdiv.
y; j++) {
1981 for (
uint i = 0; i < subdiv.
x; i++) {
1982 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);
1987 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
elevation,
"x");
1989 if (rotation.
azimuth != 0.f) {
1990 getPrimitivePointer_private(UUID[t])->rotate(-rotation.
azimuth,
"z");
1992 getPrimitivePointer_private(UUID[t])->translate(center);
2002 return addTile(center, size, rotation, subdiv, texturefile,
make_int2(1, 1));
2006 if (!validateTextureFileExtenstion(texturefile)) {
2007 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2008 }
else if (!doesTextureFileExist(texturefile)) {
2009 helios_runtime_error(
"ERROR (Context::addTile): Texture file " + std::string(texturefile) +
" does not exist.");
2010 }
else if (texture_repeat.
x < 1 || texture_repeat.
y < 1) {
2011 helios_runtime_error(
"ERROR (Context::addTile): Number of texture repeats must be greater than 0.");
2015 int2 repeat = texture_repeat;
2016 repeat.
x = std::min(subdiv.
x, repeat.
x);
2017 repeat.
y = std::min(subdiv.
y, repeat.
y);
2018 while (subdiv.
x % repeat.
x != 0) {
2021 while (subdiv.
y % repeat.
y != 0) {
2025 std::vector<uint> UUID;
2028 subsize.
x = size.
x / float(subdiv.
x);
2029 subsize.
y = size.
y / float(subdiv.
y);
2031 std::vector<helios::vec2> uv(4);
2032 int2 sub_per_repeat;
2033 sub_per_repeat.
x = subdiv.
x / repeat.
x;
2034 sub_per_repeat.
y = subdiv.
y / repeat.
y;
2036 uv_sub.
x = 1.f / float(sub_per_repeat.
x);
2037 uv_sub.
y = 1.f / float(sub_per_repeat.
y);
2039 addTexture(texturefile);
2041 const int2 &sz = textures.at(texturefile).getImageResolution();
2042 if (subdiv.
x >= repeat.
x * sz.
x || subdiv.
y >= repeat.
y * sz.
y) {
2043 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.");
2046 for (
uint j = 0; j < subdiv.
y; j++) {
2047 for (
uint i = 0; i < subdiv.
x; i++) {
2048 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);
2050 uint i_local = i % sub_per_repeat.
x;
2051 uint j_local = j % sub_per_repeat.
y;
2052 uv.at(0) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local) * uv_sub.
y);
2053 uv.at(1) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local) * uv_sub.
y);
2054 uv.at(2) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
2055 uv.at(3) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
2057 auto *patch_new = (
new Patch(texturefile, uv, textures, 0, currentUUID));
2059 if (patch_new->getSolidFraction() == 0) {
2064 assert(size.
x > 0.f && size.
y > 0.f);
2065 patch_new->scale(
make_vec3(subsize.
x, subsize.
y, 1));
2067 patch_new->translate(subcenter);
2070 patch_new->rotate(-rotation.
elevation,
"x");
2073 patch_new->rotate(-rotation.
azimuth,
"z");
2076 patch_new->translate(center);
2078 primitives[currentUUID] = patch_new;
2081 patch_new->context_ptr =
this;
2082 patch_new->materialID = 0;
2084 materials[0].reference_count++;
2087 UUID.push_back(currentUUID - 1);
2095 std::vector<RGBcolor> color(nodes.size(),
make_RGBcolor(0.f, 0.75f, 0.f));
2097 return addTube(Ndivs, nodes, radius, color);
2100std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const std::vector<RGBcolor> &color) {
2101 const uint node_count = nodes.size();
2103 if (node_count == 0) {
2105 }
else if (node_count != radius.size()) {
2106 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2107 }
else if (node_count != color.size()) {
2108 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `color' arguments must agree.");
2112 std::vector<float> cfact(radial_subdivisions + 1);
2113 std::vector<float> sfact(radial_subdivisions + 1);
2114 std::vector<std::vector<vec3>> xyz;
2117 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2119 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2120 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2121 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2124 for (
int i = 0; i < node_count; i++) {
2126 if (radius.at(i) < 0) {
2131 vec.
x = nodes[i + 1].x - nodes[i].x;
2132 vec.
y = nodes[i + 1].y - nodes[i].y;
2133 vec.
z = nodes[i + 1].z - nodes[i].z;
2134 }
else if (i == node_count - 1) {
2135 vec.
x = nodes[i].x - nodes[i - 1].x;
2136 vec.
y = nodes[i].y - nodes[i - 1].y;
2137 vec.
z = nodes[i].z - nodes[i - 1].z;
2139 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2140 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2141 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2146 if (fabs(nvec * vec) > 0.95f) {
2147 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2148 if (fabs(nvec * vec) > 0.95f) {
2149 nvec =
vec3(1.0f, 0.0f, 0.0f);
2153 if (fabs(vec.z) > 0.95f) {
2154 nvec =
vec3(1.0f, 0.0f, 0.0f);
2157 convec =
cross(nvec, vec);
2159 nvec =
cross(vec, convec);
2162 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2164 normal.
x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2165 normal.
y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2166 normal.
z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2168 xyz[j][i].x = nodes[i].x + normal.
x;
2169 xyz[j][i].y = nodes[i].y + normal.
y;
2170 xyz[j][i].z = nodes[i].z + normal.
z;
2175 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2178 for (
int i = 0; i < node_count - 1; i++) {
2179 for (
int j = 0; j < radial_subdivisions; j++) {
2181 v1 = xyz[j + 1][i + 1];
2184 UUIDs.at(ii) =
addTriangle(v0, v1, v2, color.at(i));
2188 v2 = xyz[j + 1][i + 1];
2190 UUIDs.at(ii + 1) =
addTriangle(v0, v1, v2, color.at(i));
2199std::vector<uint>
Context::addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile) {
2200 if (!validateTextureFileExtenstion(texturefile)) {
2201 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2202 }
else if (!doesTextureFileExist(texturefile)) {
2203 helios_runtime_error(
"ERROR (Context::addTube): Texture file " + std::string(texturefile) +
" does not exist.");
2206 const uint node_count = nodes.size();
2208 if (node_count == 0) {
2210 }
else if (node_count != radius.size()) {
2211 helios_runtime_error(
"ERROR (Context::addTube): Size of `nodes' and `radius' arguments must agree.");
2215 std::vector<float> cfact(radial_subdivisions + 1);
2216 std::vector<float> sfact(radial_subdivisions + 1);
2217 std::vector<std::vector<vec3>> xyz, normal;
2218 std::vector<std::vector<vec2>> uv;
2223 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2225 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2226 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2227 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2230 for (
int i = 0; i < node_count; i++) {
2232 if (radius.at(i) < 0) {
2237 vec.
x = nodes[i + 1].x - nodes[i].x;
2238 vec.
y = nodes[i + 1].y - nodes[i].y;
2239 vec.
z = nodes[i + 1].z - nodes[i].z;
2240 }
else if (i == node_count - 1) {
2241 vec.
x = nodes[i].x - nodes[i - 1].x;
2242 vec.
y = nodes[i].y - nodes[i - 1].y;
2243 vec.
z = nodes[i].z - nodes[i - 1].z;
2245 vec.
x = 0.5f * ((nodes[i].x - nodes[i - 1].x) + (nodes[i + 1].x - nodes[i].x));
2246 vec.
y = 0.5f * ((nodes[i].y - nodes[i - 1].y) + (nodes[i + 1].y - nodes[i].y));
2247 vec.
z = 0.5f * ((nodes[i].z - nodes[i - 1].z) + (nodes[i + 1].z - nodes[i].z));
2252 if (fabs(nvec * vec) > 0.95f) {
2253 nvec =
vec3(0.1817f, 0.6198f, 0.7634f);
2254 if (fabs(nvec * vec) > 0.95f) {
2255 nvec =
vec3(1.0f, 0.0f, 0.0f);
2259 if (fabs(vec.z) > 0.95f) {
2260 nvec =
vec3(1.0f, 0.0f, 0.0f);
2263 convec =
cross(nvec, vec);
2265 nvec =
cross(vec, convec);
2268 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2269 normal[j][i].
x = cfact[j] * radius[i] * nvec.
x + sfact[j] * radius[i] * convec.
x;
2270 normal[j][i].y = cfact[j] * radius[i] * nvec.
y + sfact[j] * radius[i] * convec.
y;
2271 normal[j][i].z = cfact[j] * radius[i] * nvec.
z + sfact[j] * radius[i] * convec.
z;
2273 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2274 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2275 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2277 uv[j][i].x = float(i) / float(node_count - 1);
2278 uv[j][i].y = float(j) / float(radial_subdivisions);
2280 normal[j][i] = normal[j][i] / radius[i];
2286 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
2289 for (
int i = 0; i < node_count - 1; i++) {
2290 for (
int j = 0; j < radial_subdivisions; j++) {
2292 v1 = xyz[j + 1][i + 1];
2296 uv1 = uv[j + 1][i + 1];
2299 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2301 UUIDs.at(ii) = triangle_uuid;
2309 v2 = xyz[j + 1][i + 1];
2313 uv2 = uv[j + 1][i + 1];
2315 uint triangle_uuid2 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2317 UUIDs.at(ii + 1) = triangle_uuid2;
2320 UUIDs.at(ii + 1) = 0;
2328 UUIDs.erase(std::remove(UUIDs.begin(), UUIDs.end(), 0), UUIDs.end());
2336 return addBox(center, size, subdiv, color,
false);
2340 return addBox(center, size, subdiv, color,
false);
2344 return addBox(center, size, subdiv, texturefile,
false);
2348 std::vector<uint> UUID;
2351 subsize.
x = size.
x / float(subdiv.
x);
2352 subsize.
y = size.
y / float(subdiv.
y);
2353 subsize.
z = size.
z / float(subdiv.
z);
2356 std::vector<uint> U;
2358 if (reverse_normals) {
2363 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2365 UUID.insert(UUID.end(), U.begin(), U.end());
2368 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2370 UUID.insert(UUID.end(), U.begin(), U.end());
2375 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2377 UUID.insert(UUID.end(), U.begin(), U.end());
2380 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2382 UUID.insert(UUID.end(), U.begin(), U.end());
2387 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2389 UUID.insert(UUID.end(), U.begin(), U.end());
2392 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2394 UUID.insert(UUID.end(), U.begin(), U.end());
2400 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2402 UUID.insert(UUID.end(), U.begin(), U.end());
2405 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2407 UUID.insert(UUID.end(), U.begin(), U.end());
2412 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2414 UUID.insert(UUID.end(), U.begin(), U.end());
2417 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2419 UUID.insert(UUID.end(), U.begin(), U.end());
2424 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2426 UUID.insert(UUID.end(), U.begin(), U.end());
2429 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2431 UUID.insert(UUID.end(), U.begin(), U.end());
2438 if (!validateTextureFileExtenstion(texturefile)) {
2439 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2440 }
else if (!doesTextureFileExist(texturefile)) {
2441 helios_runtime_error(
"ERROR (Context::addBox): Texture file " + std::string(texturefile) +
" does not exist.");
2444 std::vector<uint> UUID;
2447 subsize.
x = size.
x / float(subdiv.
x);
2448 subsize.
y = size.
y / float(subdiv.
y);
2449 subsize.
z = size.
z / float(subdiv.
z);
2452 std::vector<uint> U;
2454 if (reverse_normals) {
2459 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2461 UUID.insert(UUID.end(), U.begin(), U.end());
2464 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2466 UUID.insert(UUID.end(), U.begin(), U.end());
2471 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2473 UUID.insert(UUID.end(), U.begin(), U.end());
2476 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2478 UUID.insert(UUID.end(), U.begin(), U.end());
2483 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2485 UUID.insert(UUID.end(), U.begin(), U.end());
2488 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2490 UUID.insert(UUID.end(), U.begin(), U.end());
2496 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
2498 UUID.insert(UUID.end(), U.begin(), U.end());
2501 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
2503 UUID.insert(UUID.end(), U.begin(), U.end());
2508 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
2510 UUID.insert(UUID.end(), U.begin(), U.end());
2513 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
2515 UUID.insert(UUID.end(), U.begin(), U.end());
2520 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
2522 UUID.insert(UUID.end(), U.begin(), U.end());
2525 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
2527 UUID.insert(UUID.end(), U.begin(), U.end());
2558 std::vector<uint> UUID(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2560 for (
int r = 0; r < Ndivs.
y; r++) {
2561 for (
int t = 0; t < Ndivs.
x; t++) {
2562 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2563 float theta = dtheta * float(t);
2564 float theta_plus = dtheta * float(t + 1);
2566 float rx = size.
x / float(Ndivs.
y) * float(r);
2567 float ry = size.
y / float(Ndivs.
y) * float(r);
2569 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2570 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2575 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);
2577 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);
2579 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
elevation,
"y");
2580 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
azimuth,
"z");
2581 getPrimitivePointer_private(UUID.at(i))->translate(center);
2591 if (!validateTextureFileExtenstion(texturefile)) {
2592 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2593 }
else if (!doesTextureFileExist(texturefile)) {
2594 helios_runtime_error(
"ERROR (Context::addDisk): Texture file " + std::string(texturefile) +
" does not exist.");
2597 std::vector<uint> UUID;
2598 UUID.reserve(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
2599 for (
int r = 0; r < Ndivs.
y; r++) {
2600 for (
int t = 0; t < Ndivs.
x; t++) {
2601 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
2602 float theta = dtheta * float(t);
2603 float theta_plus = dtheta * float(t + 1);
2605 float rx = size.
x / float(Ndivs.
y) * float(r);
2606 float ry = size.
y / float(Ndivs.
y) * float(r);
2607 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
2608 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
2611 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),
2612 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
2613 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2615 UUID.push_back(triangle_uuid);
2621 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,
2622 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)),
2623 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)));
2625 UUID.push_back(triangle_uuid1);
2630 uint triangle_uuid2 =
2631 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,
2632 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)),
2633 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
2635 UUID.push_back(triangle_uuid2);
2642 size_t start_idx = UUID.size() - (r == 0 ? 1 : 2);
2643 for (
size_t uuid_idx = start_idx; uuid_idx < UUID.size(); uuid_idx++) {
2644 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
elevation,
"y");
2645 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
azimuth,
"z");
2646 getPrimitivePointer_private(UUID.at(uuid_idx))->translate(center);
2658 return addCone(Ndivs, node0, node1, radius0, radius1, color);
2662 std::vector<helios::vec3> nodes{node0, node1};
2663 std::vector<float> radii{radius0, radius1};
2666 std::vector<float> cfact(Ndivs + 1);
2667 std::vector<float> sfact(Ndivs + 1);
2668 std::vector<std::vector<vec3>> xyz, normal;
2669 xyz.resize(Ndivs + 1);
2670 normal.resize(Ndivs + 1);
2671 for (
uint j = 0; j < Ndivs + 1; j++) {
2672 xyz.at(j).resize(2);
2673 normal.at(j).resize(2);
2675 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
2677 for (
int j = 0; j < Ndivs + 1; j++) {
2678 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2679 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2682 for (
int i = 0; i < 2; i++) {
2685 vec.
x = nodes[i + 1].x - nodes[i].x;
2686 vec.
y = nodes[i + 1].y - nodes[i].y;
2687 vec.
z = nodes[i + 1].z - nodes[i].z;
2688 }
else if (i == 1) {
2689 vec.
x = nodes[i].x - nodes[i - 1].x;
2690 vec.
y = nodes[i].y - nodes[i - 1].y;
2691 vec.
z = nodes[i].z - nodes[i - 1].z;
2695 convec =
cross(nvec, vec);
2697 convec.
x = convec.
x / norm;
2698 convec.
y = convec.
y / norm;
2699 convec.
z = convec.
z / norm;
2700 nvec =
cross(vec, convec);
2702 nvec.
x = nvec.
x / norm;
2703 nvec.
y = nvec.
y / norm;
2704 nvec.
z = nvec.
z / norm;
2707 for (
int j = 0; j < Ndivs + 1; j++) {
2708 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2709 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2710 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2712 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2713 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2714 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2716 normal[j][i] = normal[j][i] / radii[i];
2721 std::vector<uint> UUID;
2723 for (
int i = 0; i < 2 - 1; i++) {
2724 for (
int j = 0; j < Ndivs; j++) {
2726 v1 = xyz[j + 1][i + 1];
2733 v2 = xyz[j + 1][i + 1];
2743 if (!validateTextureFileExtenstion(texturefile)) {
2744 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
2745 }
else if (!doesTextureFileExist(texturefile)) {
2746 helios_runtime_error(
"ERROR (Context::addCone): Texture file " + std::string(texturefile) +
" does not exist.");
2749 std::vector<helios::vec3> nodes{node0, node1};
2750 std::vector<float> radii{radius0, radius1};
2753 std::vector<float> cfact(Ndivs + 1);
2754 std::vector<float> sfact(Ndivs + 1);
2755 std::vector<std::vector<vec3>> xyz, normal;
2756 std::vector<std::vector<vec2>> uv;
2757 xyz.resize(Ndivs + 1);
2758 normal.resize(Ndivs + 1);
2759 uv.resize(Ndivs + 1);
2760 for (
uint j = 0; j < Ndivs + 1; j++) {
2761 xyz.at(j).resize(2);
2762 normal.at(j).resize(2);
2765 vec3 nvec(0.f, 1.f, 0.f);
2767 for (
int j = 0; j < Ndivs + 1; j++) {
2768 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
2769 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
2772 for (
int i = 0; i < 2; i++) {
2775 vec.
x = nodes[i + 1].x - nodes[i].x;
2776 vec.
y = nodes[i + 1].y - nodes[i].y;
2777 vec.
z = nodes[i + 1].z - nodes[i].z;
2778 }
else if (i == 1) {
2779 vec.
x = nodes[i].x - nodes[i - 1].x;
2780 vec.
y = nodes[i].y - nodes[i - 1].y;
2781 vec.
z = nodes[i].z - nodes[i - 1].z;
2785 convec =
cross(nvec, vec);
2787 convec.
x = convec.
x / norm;
2788 convec.
y = convec.
y / norm;
2789 convec.
z = convec.
z / norm;
2790 nvec =
cross(vec, convec);
2792 nvec.
x = nvec.
x / norm;
2793 nvec.
y = nvec.
y / norm;
2794 nvec.
z = nvec.
z / norm;
2796 for (
int j = 0; j < Ndivs + 1; j++) {
2797 normal[j][i].x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
2798 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
2799 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
2801 xyz[j][i].x = nodes[i].x + normal[j][i].x;
2802 xyz[j][i].y = nodes[i].y + normal[j][i].y;
2803 xyz[j][i].z = nodes[i].z + normal[j][i].z;
2805 uv[j][i].x = float(i) / float(2 - 1);
2806 uv[j][i].y = float(j) / float(Ndivs);
2808 normal[j][i] = normal[j][i] / radii[i];
2814 std::vector<uint> UUID;
2816 for (
int i = 0; i < 2 - 1; i++) {
2817 for (
int j = 0; j < Ndivs; j++) {
2819 v1 = xyz[j + 1][i + 1];
2823 uv1 = uv[j + 1][i + 1];
2826 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2827 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2829 UUID.push_back(triangle_uuid);
2837 v2 = xyz[j + 1][i + 1];
2841 uv2 = uv[j + 1][i + 1];
2843 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
2844 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
2846 UUID.push_back(triangle_uuid);
2862 std::map<uint, float> pcolor_data;
2865 float data_min_new = 9999999;
2866 float data_max_new = -9999999;
2867 for (
uint UUID: UUIDs) {
2869 warnings.
addWarning(
"primitive_does_not_exist",
"Primitive for UUID " + std::to_string(UUID) +
" does not exist. Skipping this primitive.");
2877 warnings.
addWarning(
"unsupported_data_type",
"Only primitive data types of int, uint, float, and double are supported for this function. Skipping this primitive.");
2888 dataf = float(data);
2892 dataf = float(data);
2896 dataf = float(data);
2900 if (data_min == 9999999 && data_max == -9999999) {
2901 if (dataf < data_min_new) {
2902 data_min_new = dataf;
2904 if (dataf > data_max_new) {
2905 data_max_new = dataf;
2909 pcolor_data[UUID] = dataf;
2912 if (data_min == 9999999 && data_max == -9999999) {
2913 data_min = data_min_new;
2914 data_max = data_max_new;
2919 std::map<std::string, std::vector<std::string>> cmap_texture_filenames;
2921 for (
auto &[UUID, pdata]: pcolor_data) {
2924 int cmap_ind = std::round((pdata - data_min) / (data_max - data_min) *
float(Ncolors - 1));
2928 }
else if (cmap_ind >= Ncolors) {
2929 cmap_ind = Ncolors - 1;
2946 warnings.
report(std::cerr);
2950 if (Ncolors > 9999) {
2951 std::cerr <<
"WARNING (Context::generateColormap): Truncating number of color map textures to maximum value of 9999." << std::endl;
2954 if (ctable.size() != cfrac.size()) {
2955 helios_runtime_error(
"ERROR (Context::generateColormap): The length of arguments 'ctable' and 'cfrac' must match.");
2957 if (ctable.empty()) {
2958 helios_runtime_error(
"ERROR (Context::generateColormap): 'ctable' and 'cfrac' arguments contain empty vectors.");
2961 std::vector<RGBcolor> color_table(Ncolors);
2963 for (
int i = 0; i < Ncolors; i++) {
2964 float frac = float(i) / float(Ncolors - 1) * cfrac.back();
2967 for (j = 0; j < cfrac.size() - 1; j++) {
2968 if (frac >= cfrac.at(j) && frac <= cfrac.at(j + 1)) {
2973 float cminus = std::fmaxf(0.f, cfrac.at(j));
2974 float cplus = std::fminf(1.f, cfrac.at(j + 1));
2976 float jfrac = (frac - cminus) / (cplus - cminus);
2979 color.
r = ctable.at(j).r + jfrac * (ctable.at(j + 1).r - ctable.at(j).r);
2980 color.
g = ctable.at(j).g + jfrac * (ctable.at(j + 1).g - ctable.at(j).g);
2981 color.
b = ctable.at(j).b + jfrac * (ctable.at(j + 1).b - ctable.at(j).b);
2983 color_table.at(i) = color;
2990 std::vector<RGBcolor> ctable_c;
2991 std::vector<float> clocs_c;
2993 if (colormap ==
"hot") {
3002 clocs_c.at(0) = 0.f;
3003 clocs_c.at(1) = 0.25f;
3004 clocs_c.at(2) = 0.5f;
3005 clocs_c.at(3) = 0.75f;
3006 clocs_c.at(4) = 1.f;
3007 }
else if (colormap ==
"cool") {
3009 ctable_c.at(0) = RGB::cyan;
3010 ctable_c.at(1) = RGB::magenta;
3013 clocs_c.at(0) = 0.f;
3014 clocs_c.at(1) = 1.f;
3015 }
else if (colormap ==
"lava") {
3024 clocs_c.at(0) = 0.f;
3025 clocs_c.at(1) = 0.4f;
3026 clocs_c.at(2) = 0.5f;
3027 clocs_c.at(3) = 0.6f;
3028 clocs_c.at(4) = 1.f;
3029 }
else if (colormap ==
"rainbow") {
3031 ctable_c.at(0) = RGB::navy;
3032 ctable_c.at(1) = RGB::cyan;
3033 ctable_c.at(2) = RGB::yellow;
3037 clocs_c.at(0) = 0.f;
3038 clocs_c.at(1) = 0.3f;
3039 clocs_c.at(2) = 0.7f;
3040 clocs_c.at(3) = 1.f;
3041 }
else if (colormap ==
"parula") {
3043 ctable_c.at(0) = RGB::navy;
3045 ctable_c.at(2) = RGB::goldenrod;
3046 ctable_c.at(3) = RGB::yellow;
3049 clocs_c.at(0) = 0.f;
3050 clocs_c.at(1) = 0.4f;
3051 clocs_c.at(2) = 0.7f;
3052 clocs_c.at(3) = 1.f;
3053 }
else if (colormap ==
"gray") {
3055 ctable_c.at(0) = RGB::black;
3056 ctable_c.at(1) = RGB::white;
3059 clocs_c.at(0) = 0.f;
3060 clocs_c.at(1) = 1.f;
3061 }
else if (colormap ==
"green") {
3063 ctable_c.at(0) = RGB::black;
3064 ctable_c.at(1) = RGB::green;
3067 clocs_c.at(0) = 0.f;
3068 clocs_c.at(1) = 1.f;
3070 helios_runtime_error(
"ERROR (Context::generateColormapTextures): Unknown colormap " + colormap +
".");
3077 uint Ncolors = colormap_data.size();
3080 std::ifstream tfile(texturefile);
3082 helios_runtime_error(
"ERROR (Context::generateTexturesFromColormap): Texture file " + texturefile +
" does not exist, or you do not have permission to read it.");
3092 std::vector<RGBcolor> color_table(Ncolors);
3094 std::vector<std::string> texture_filenames(Ncolors);
3096 if (file_ext ==
"png" || file_ext ==
"PNG") {
3097 std::vector<RGBAcolor> pixel_data;
3099 readPNG(texturefile, width, height, pixel_data);
3101 for (
int i = 0; i < Ncolors; i++) {
3102 std::ostringstream filename;
3103 filename <<
"lib/images/colormap_" << file_base <<
"_" << std::setw(4) << std::setfill(
'0') << std::to_string(i) <<
".png";
3105 texture_filenames.at(i) = filename.str();
3107 RGBcolor color = colormap_data.at(i);
3109 for (
int row = 0; row < height; row++) {
3110 for (
int col = 0; col < width; col++) {
3111 pixel_data.at(row * width + col) =
make_RGBAcolor(color, pixel_data.at(row * width + col).a);
3115 writePNG(filename.str(), width, height, pixel_data);
3119 return texture_filenames;
3122void Context::out_of_memory_handler() {
3123 helios_runtime_error(
"ERROR: Out of host memory. The program has run out of memory and cannot continue.");
3126void Context::install_out_of_memory_handler() {
3127 std::set_new_handler(out_of_memory_handler);
3131 for (
auto &[UUID, primitive]: primitives) {
3132 delete getPrimitivePointer_private(UUID);
3135 for (
auto &[UUID,
object]: objects) {
3136 delete getObjectPointer_private(UUID);
3143 helios_runtime_error(
"ERROR (Context::getPrimitiveType): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3146 return getPrimitivePointer_private(UUID)->getType();
3152 helios_runtime_error(
"ERROR (Context::setPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3156 uint current_objID = getPrimitivePointer_private(UUID)->getParentObjectID();
3157 getPrimitivePointer_private(UUID)->setParentObjectID(objID);
3159 if (current_objID != 0u && current_objID != objID) {
3161 objects.at(current_objID)->deleteChildPrimitive(UUID);
3163 if (getObjectPointer_private(current_objID)->getPrimitiveUUIDs().empty()) {
3166 objects.erase(current_objID);
3173 for (
uint UUID: UUIDs) {
3181 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3184 return getPrimitivePointer_private(UUID)->getParentObjectID();
3188 std::vector<uint> objIDs(UUIDs.size());
3189 for (
uint i = 0; i < UUIDs.size(); i++) {
3192 helios_runtime_error(
"ERROR (Context::getPrimitiveParentObjectID): Primitive with UUID of " + std::to_string(UUIDs[i]) +
" does not exist in the Context.");
3195 objIDs[i] = getPrimitivePointer_private(UUIDs[i])->getParentObjectID();
3207 std::vector<uint> primitiveObjIDs;
3208 if (UUIDs.empty()) {
3209 return primitiveObjIDs;
3213 primitiveObjIDs.resize(UUIDs.size());
3214 for (
uint i = 0; i < UUIDs.size(); i++) {
3217 helios_runtime_error(
"ERROR (Context::getUniquePrimitiveParentObjectIDs): Primitive with UUID of " + std::to_string(UUIDs.at(i)) +
" does not exist in the Context.");
3220 primitiveObjIDs.at(i) = getPrimitivePointer_private(UUIDs.at(i))->getParentObjectID();
3224 std::sort(primitiveObjIDs.begin(), primitiveObjIDs.end());
3227 auto it = unique(primitiveObjIDs.begin(), primitiveObjIDs.end());
3228 primitiveObjIDs.resize(distance(primitiveObjIDs.begin(), it));
3231 if (include_ObjID_zero ==
false & primitiveObjIDs.front() ==
uint(0)) {
3232 primitiveObjIDs.erase(primitiveObjIDs.begin());
3235 return primitiveObjIDs;
3241 helios_runtime_error(
"ERROR (Context::getPrimitiveArea): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3244 return getPrimitivePointer_private(UUID)->getArea();
3248 const std::vector UUIDs = {UUID};
3254 for (
uint UUID: UUIDs) {
3256 helios_runtime_error(
"ERROR (Context::getPrimitiveBoundingBox): Primitive with UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3262 min_corner = vertices.front();
3263 max_corner = min_corner;
3266 for (
const vec3 &vert: vertices) {
3267 if (vert.x < min_corner.
x) {
3268 min_corner.
x = vert.x;
3270 if (vert.y < min_corner.
y) {
3271 min_corner.
y = vert.y;
3273 if (vert.z < min_corner.
z) {
3274 min_corner.
z = vert.z;
3276 if (vert.x > max_corner.
x) {
3277 max_corner.
x = vert.x;
3279 if (vert.y > max_corner.
y) {
3280 max_corner.
y = vert.y;
3282 if (vert.z > max_corner.
z) {
3283 max_corner.
z = vert.z;
3292 return getPrimitivePointer_private(UUID)->getNormal();
3296 getPrimitivePointer_private(UUID)->getTransformationMatrix(T);
3300 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3304 for (
uint UUID: UUIDs) {
3305 getPrimitivePointer_private(UUID)->setTransformationMatrix(T);
3310 return getPrimitivePointer_private(UUID)->getVertices();
3315 return getPrimitivePointer_private(UUID)->getColor();
3319 return getPrimitivePointer_private(UUID)->getColorRGB();
3323 return getPrimitivePointer_private(UUID)->getColorRGBA();
3327 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3328 getPrimitivePointer_private(UUID)->setColor(color);
3332 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3333 for (
uint UUID: UUIDs) {
3334 getPrimitivePointer_private(UUID)->setColor(color);
3339 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3340 getPrimitivePointer_private(UUID)->setColor(color);
3344 api_warnings.
addWarning(
"setPrimitiveColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3345 for (
uint UUID: UUIDs) {
3346 getPrimitivePointer_private(UUID)->setColor(color);
3351 return getPrimitivePointer_private(UUID)->getTextureFile();
3355 api_warnings.
addWarning(
"setPrimitiveTextureFile_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3356 getPrimitivePointer_private(UUID)->setTextureFile(texturefile.c_str());
3360 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3361 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3362 return textures.at(texturefile).getImageResolution();
3368 return getPrimitivePointer_private(UUID)->getTextureUV();
3372 std::string texturefile = getPrimitivePointer_private(UUID)->getTextureFile();
3373 if (!texturefile.empty() && textures.find(texturefile) != textures.end()) {
3374 return textures.at(texturefile).hasTransparencyChannel();
3381 const std::vector<std::vector<bool>> *data = textures.at(getPrimitivePointer_private(UUID)->getTextureFile()).getTransparencyData();
3385 helios_runtime_error(
"ERROR (Context::getPrimitiveTransparencyData): Texture transparency data does not exist for primitive " + std::to_string(UUID) +
".");
3390 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3391 getPrimitivePointer_private(UUID)->overrideTextureColor();
3395 api_warnings.
addWarning(
"overridePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3396 for (
uint UUID: UUIDs) {
3397 getPrimitivePointer_private(UUID)->overrideTextureColor();
3402 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3403 getPrimitivePointer_private(UUID)->useTextureColor();
3407 api_warnings.
addWarning(
"usePrimitiveTextureColor_inefficient_api",
"This method creates per-primitive materials. For better memory efficiency, use addMaterial() + assignMaterialToPrimitive().");
3408 for (
uint UUID: UUIDs) {
3409 getPrimitivePointer_private(UUID)->useTextureColor();
3414 return getPrimitivePointer_private(UUID)->isTextureColorOverridden();
3418 return getPrimitivePointer_private(UUID)->getSolidFraction();
3422 std::cout <<
"-------------------------------------------" << std::endl;
3423 std::cout <<
"Info for UUID " << UUID << std::endl;
3424 std::cout <<
"-------------------------------------------" << std::endl;
3429 stype =
"PRIMITIVE_TYPE_PATCH";
3430 }
else if (type == 1) {
3431 stype =
"PRIMITIVE_TYPE_TRIANGLE";
3432 }
else if (type == 2) {
3433 stype =
"PRIMITIVE_TYPE_VOXEL";
3436 std::cout <<
"Type: " << stype << std::endl;
3442 std::cout <<
"Patch Center: " <<
getPatchCenter(UUID) << std::endl;
3443 std::cout <<
"Patch Size: " <<
getPatchSize(UUID) << std::endl;
3445 std::cout <<
"Voxel Center: " <<
getVoxelCenter(UUID) << std::endl;
3446 std::cout <<
"Voxel Size: " <<
getVoxelSize(UUID) << std::endl;
3450 std::cout <<
"Vertices: " << std::endl;
3451 for (
uint i = 0; i < primitive_vertices.size(); i++) {
3452 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
3457 std::cout <<
"Transform: " << std::endl;
3458 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
3459 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
3460 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
3461 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
3466 std::cout <<
"Texture UV: " << std::endl;
3468 for (
uint i = 0; i < uv.size(); i++) {
3469 std::cout <<
" " << uv.at(i) << std::endl;
3477 std::cout <<
"Primitive Data: " << std::endl;
3480 for (
uint i = 0; i < pd.size(); i++) {
3486 dstype =
"HELIOS_TYPE_INT";
3488 dstype =
"HELIOS_TYPE_UINT";
3490 dstype =
"HELIOS_TYPE_FLOAT";
3492 dstype =
"HELIOS_TYPE_DOUBLE";
3494 dstype =
"HELIOS_TYPE_VEC2";
3496 dstype =
"HELIOS_TYPE_VEC3";
3498 dstype =
"HELIOS_TYPE_VEC4";
3500 dstype =
"HELIOS_TYPE_INT2";
3502 dstype =
"HELIOS_TYPE_INT3";
3504 dstype =
"HELIOS_TYPE_INT4";
3506 dstype =
"HELIOS_TYPE_STRING";
3512 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
3516 std::vector<int> pdata;
3518 for (
uint j = 0; j < dsize; j++) {
3520 std::cout <<
" " << pdata.at(j) << std::endl;
3522 std::cout <<
" ..." << std::endl;
3523 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3524 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3529 std::vector<uint> pdata;
3531 for (
uint j = 0; j < dsize; j++) {
3533 std::cout <<
" " << pdata.at(j) << std::endl;
3535 std::cout <<
" ..." << std::endl;
3536 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3537 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3542 std::vector<float> pdata;
3544 for (
uint j = 0; j < dsize; j++) {
3546 std::cout <<
" " << pdata.at(j) << std::endl;
3548 std::cout <<
" ..." << std::endl;
3549 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3550 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3555 std::vector<double> pdata;
3557 for (
uint j = 0; j < dsize; j++) {
3559 std::cout <<
" " << pdata.at(j) << std::endl;
3561 std::cout <<
" ..." << std::endl;
3562 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3563 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3568 std::vector<vec2> pdata;
3570 for (
uint j = 0; j < dsize; j++) {
3572 std::cout <<
" " << pdata.at(j) << std::endl;
3574 std::cout <<
" ..." << std::endl;
3575 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3576 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3581 std::vector<vec3> pdata;
3583 for (
uint j = 0; j < dsize; j++) {
3585 std::cout <<
" " << pdata.at(j) << std::endl;
3587 std::cout <<
" ..." << std::endl;
3588 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3589 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3594 std::vector<vec4> pdata;
3596 for (
uint j = 0; j < dsize; j++) {
3598 std::cout <<
" " << pdata.at(j) << std::endl;
3600 std::cout <<
" ..." << std::endl;
3601 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3602 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3607 std::vector<int2> pdata;
3609 for (
uint j = 0; j < dsize; j++) {
3611 std::cout <<
" " << pdata.at(j) << std::endl;
3613 std::cout <<
" ..." << std::endl;
3614 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3615 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3620 std::vector<int3> pdata;
3622 for (
uint j = 0; j < dsize; j++) {
3624 std::cout <<
" " << pdata.at(j) << std::endl;
3626 std::cout <<
" ..." << std::endl;
3627 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3628 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3633 std::vector<int4> pdata;
3635 for (
uint j = 0; j < dsize; j++) {
3637 std::cout <<
" " << pdata.at(j) << std::endl;
3639 std::cout <<
" ..." << std::endl;
3640 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3641 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3646 std::vector<std::string> pdata;
3648 for (
uint j = 0; j < dsize; j++) {
3650 std::cout <<
" " << pdata.at(j) << std::endl;
3652 std::cout <<
" ..." << std::endl;
3653 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
3654 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
3662 std::cout <<
"-------------------------------------------" << std::endl;
3668 auto it = material_label_to_id.find(material_label);
3669 if (it == material_label_to_id.end()) {
3670 helios_runtime_error(
"ERROR (Context::getMaterialIDFromLabel): Material with label '" + material_label +
"' does not exist.");
3676 if (material_label.empty()) {
3681 if (material_label.substr(0, 2) ==
"__" && material_label != DEFAULT_MATERIAL_LABEL) {
3682 helios_runtime_error(
"ERROR (Context::addMaterial): Material labels starting with '__' are reserved for internal use.");
3686 if (material_label_to_id.find(material_label) != material_label_to_id.end()) {
3687 std::cerr <<
"WARNING (Context::addMaterial): Material with label '" << material_label <<
"' already exists. Overwriting." << std::endl;
3689 uint oldID = material_label_to_id[material_label];
3690 materials.erase(oldID);
3694 uint newID = currentMaterialID++;
3696 materials[newID] = newMaterial;
3697 material_label_to_id[material_label] = newID;
3700uint Context::addMaterial_internal(
const std::string &label,
const RGBAcolor &color,
const std::string &texture) {
3702 if (label.empty()) {
3703 helios_runtime_error(
"ERROR (Context::addMaterial_internal): Material label cannot be empty.");
3707 if (material_label_to_id.find(label) != material_label_to_id.end()) {
3708 uint oldID = material_label_to_id[label];
3709 materials.erase(oldID);
3713 uint newID = currentMaterialID++;
3714 Material newMaterial(newID, label, color, texture,
false);
3715 materials[newID] = newMaterial;
3716 material_label_to_id[label] = newID;
3720std::string Context::generateMaterialLabel(
const RGBAcolor &color,
const std::string &texture,
bool texture_override)
const {
3723 hash ^= std::hash<float>{}(color.
r) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3724 hash ^= std::hash<float>{}(color.
g) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3725 hash ^= std::hash<float>{}(color.
b) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3726 hash ^= std::hash<float>{}(color.
a) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3727 hash ^= std::hash<std::string>{}(texture) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3728 hash ^= std::hash<bool>{}(texture_override) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
3729 return "__auto_" + std::to_string(hash);
3732bool Context::isMaterialShared(
uint materialID)
const {
3733 if (materials.find(materialID) == materials.end()) {
3737 return materials.at(materialID).reference_count > 1;
3740uint Context::copyMaterialForPrimitive(
uint primitiveUUID) {
3741 Primitive *prim = getPrimitivePointer_private(primitiveUUID);
3742 uint oldMaterialID = prim->materialID;
3743 const Material &oldMaterial = materials.at(oldMaterialID);
3746 std::string newLabel =
"__copy_" + std::to_string(currentMaterialID) +
"_" + std::to_string(primitiveUUID);
3753 materials[newMaterialID].twosided_flag = oldMaterial.
twosided_flag;
3771 materials[oldMaterialID].reference_count--;
3772 materials[newMaterialID].reference_count = 1;
3775 prim->materialID = newMaterialID;
3777 return newMaterialID;
3781 return material_label_to_id.find(material_label) != material_label_to_id.end();
3785 std::vector<std::string> labels;
3786 labels.reserve(material_label_to_id.size());
3787 for (
const auto &pair: material_label_to_id) {
3789 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
3790 labels.push_back(pair.first);
3798 return materials.at(matID).color;
3803 return materials.at(matID).texture_file;
3808 return materials.at(matID).texture_color_overridden;
3813 materials[matID].color = color;
3819 if (!texture_file.empty()) {
3820 addTexture(texture_file.c_str());
3822 materials[matID].texture_file = texture_file;
3827 materials[matID].texture_color_overridden =
override;
3832 return materials.at(matID).twosided_flag;
3837 materials[matID].twosided_flag = twosided_flag;
3842 bool has_user_material = (mat_label.substr(0, 7) !=
"__auto_" && mat_label != DEFAULT_MATERIAL_LABEL);
3844 if (has_user_material) {
3854 return default_value;
3859 Primitive *prim = getPrimitivePointer_private(UUID);
3860 uint oldMaterialID = prim->materialID;
3862 materials[oldMaterialID].reference_count--;
3863 materials[materialID].reference_count++;
3864 prim->materialID = materialID;
3869 for (
uint UUID: UUIDs) {
3870 Primitive *prim = getPrimitivePointer_private(UUID);
3871 uint oldMaterialID = prim->materialID;
3873 materials[oldMaterialID].reference_count--;
3874 materials[materialID].reference_count++;
3875 prim->materialID = materialID;
3885 for (
uint ObjID: ObjIDs) {
3891 Primitive *prim = getPrimitivePointer_private(UUID);
3892 uint materialID = prim->materialID;
3894 if (materials.find(materialID) != materials.end()) {
3895 return materials.at(materialID).label;
3897 return DEFAULT_MATERIAL_LABEL;
3902 std::vector<uint> result;
3903 for (
const auto &pair: primitives) {
3904 if (pair.second->materialID == materialID) {
3905 result.push_back(pair.first);
3912 if (material_label == DEFAULT_MATERIAL_LABEL) {
3916 auto it = material_label_to_id.find(material_label);
3917 if (it == material_label_to_id.end()) {
3918 helios_runtime_error(
"ERROR (Context::deleteMaterial): Material with label '" + material_label +
"' does not exist.");
3921 uint materialID = it->second;
3925 if (!users.empty()) {
3926 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;
3928 for (
uint UUID: users) {
3929 Primitive *prim = getPrimitivePointer_private(UUID);
3931 materials[materialID].reference_count--;
3932 prim->materialID = 0;
3933 materials[0].reference_count++;
3938 materials.erase(materialID);
3939 material_label_to_id.erase(material_label);
3944 return materials.at(matID).doesMaterialDataExist(data_label);
3949 return materials.at(matID).getMaterialDataType(data_label);
3954 materials[matID].clearMaterialData(data_label);
3958 Primitive *prim = getPrimitivePointer_private(UUID);
3959 return prim->materialID;
3963 if (materials.find(materialID) == materials.end()) {
3964 helios_runtime_error(
"ERROR (Context::getMaterial): Material ID " + std::to_string(materialID) +
" does not exist.");
3966 return materials.at(materialID);
3972 for (
const auto &pair: material_label_to_id) {
3974 if (pair.first != DEFAULT_MATERIAL_LABEL && pair.first.substr(0, 7) !=
"__auto_") {
3982 std::cout <<
"-------------------------------------------" << std::endl;
3983 std::cout <<
"Info for ObjID " << ObjID << std::endl;
3984 std::cout <<
"-------------------------------------------" << std::endl;
3989 ostype =
"OBJECT_TYPE_TILE";
3990 }
else if (otype == 1) {
3991 ostype =
"OBJECT_TYPE_SPHERE";
3992 }
else if (otype == 2) {
3993 ostype =
"OBJECT_TYPE_TUBE";
3994 }
else if (otype == 3) {
3995 ostype =
"OBJECT_TYPE_BOX";
3996 }
else if (otype == 4) {
3997 ostype =
"OBJECT_TYPE_DISK";
3998 }
else if (otype == 5) {
3999 ostype =
"OBJECT_TYPE_POLYMESH";
4000 }
else if (otype == 6) {
4001 ostype =
"OBJECT_TYPE_CONE";
4004 std::cout <<
"Type: " << ostype << std::endl;
4005 std::cout <<
"Object Bounding Box Center: " <<
getObjectCenter(ObjID) << std::endl;
4006 std::cout <<
"One-sided Surface Area: " <<
getObjectArea(ObjID) << std::endl;
4011 std::cout <<
"Object Primitives Complete" << std::endl;
4013 std::cout <<
"Object Primitives Incomplete" << std::endl;
4016 std::cout <<
"Primitive UUIDs: " << std::endl;
4018 for (
uint i = 0; i < primitive_UUIDs.size(); i++) {
4023 pstype =
"PRIMITIVE_TYPE_PATCH";
4024 }
else if (ptype == 1) {
4025 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4027 std::cout <<
" " << primitive_UUIDs.at(i) <<
" (" << pstype <<
")" << std::endl;
4029 std::cout <<
" ..." << std::endl;
4033 pstype =
"PRIMITIVE_TYPE_PATCH";
4034 }
else if (ptype == 1) {
4035 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4037 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 2) <<
" (" << pstype <<
")" << std::endl;
4040 pstype =
"PRIMITIVE_TYPE_PATCH";
4041 }
else if (ptype == 1) {
4042 pstype =
"PRIMITIVE_TYPE_TRIANGLE";
4044 std::cout <<
" " << primitive_UUIDs.at(primitive_UUIDs.size() - 1) <<
" (" << pstype <<
")" << std::endl;
4055 std::cout <<
"Tile Texture UV: " << std::endl;
4057 for (
uint i = 0; i < uv.size(); i++) {
4058 std::cout <<
" " << uv.at(i) << std::endl;
4061 std::cout <<
"Tile Vertices: " << std::endl;
4063 for (
uint i = 0; i < primitive_vertices.size(); i++) {
4064 std::cout <<
" " << primitive_vertices.at(i) << std::endl;
4072 std::cout <<
"Tube Nodes: " << std::endl;
4074 for (
uint i = 0; i < nodes.size(); i++) {
4076 std::cout <<
" " << nodes.at(i) << std::endl;
4078 std::cout <<
" ..." << std::endl;
4079 std::cout <<
" " << nodes.at(nodes.size() - 2) << std::endl;
4080 std::cout <<
" " << nodes.at(nodes.size() - 1) << std::endl;
4084 std::cout <<
"Tube Node Radii: " << std::endl;
4086 for (
uint i = 0; i < noderadii.size(); i++) {
4088 std::cout <<
" " << noderadii.at(i) << std::endl;
4090 std::cout <<
" ..." << std::endl;
4091 std::cout <<
" " << noderadii.at(noderadii.size() - 2) << std::endl;
4092 std::cout <<
" " << noderadii.at(noderadii.size() - 1) << std::endl;
4096 std::cout <<
"Tube Node Colors: " << std::endl;
4098 for (
uint i = 0; i < nodecolors.size(); i++) {
4100 std::cout <<
" " << nodecolors.at(i) << std::endl;
4102 std::cout <<
" ..." << std::endl;
4103 std::cout <<
" " << nodecolors.at(nodecolors.size() - 2) << std::endl;
4104 std::cout <<
" " << nodecolors.at(nodecolors.size() - 1) << std::endl;
4123 std::cout <<
"Cone Nodes: " << std::endl;
4125 for (
uint i = 0; i < nodes.size(); i++) {
4126 std::cout <<
" " << nodes.at(i) << std::endl;
4128 std::cout <<
"Cone Node Radii: " << std::endl;
4130 for (
uint i = 0; i < noderadii.size(); i++) {
4131 std::cout <<
" " << noderadii.at(i) << std::endl;
4138 std::cout <<
"Transform: " << std::endl;
4139 std::cout <<
" " << T[0] <<
" " << T[1] <<
" " << T[2] <<
" " << T[3] << std::endl;
4140 std::cout <<
" " << T[4] <<
" " << T[5] <<
" " << T[6] <<
" " << T[7] << std::endl;
4141 std::cout <<
" " << T[8] <<
" " << T[9] <<
" " << T[10] <<
" " << T[11] << std::endl;
4142 std::cout <<
" " << T[12] <<
" " << T[13] <<
" " << T[14] <<
" " << T[15] << std::endl;
4146 std::cout <<
"Object Data: " << std::endl;
4149 for (
uint i = 0; i < pd.size(); i++) {
4155 dstype =
"HELIOS_TYPE_INT";
4157 dstype =
"HELIOS_TYPE_UINT";
4159 dstype =
"HELIOS_TYPE_FLOAT";
4161 dstype =
"HELIOS_TYPE_DOUBLE";
4163 dstype =
"HELIOS_TYPE_VEC2";
4165 dstype =
"HELIOS_TYPE_VEC3";
4167 dstype =
"HELIOS_TYPE_VEC4";
4169 dstype =
"HELIOS_TYPE_INT2";
4171 dstype =
"HELIOS_TYPE_INT3";
4173 dstype =
"HELIOS_TYPE_INT4";
4175 dstype =
"HELIOS_TYPE_STRING";
4181 std::cout <<
" " <<
"[name: " << pd.at(i) <<
", type: " << dstype <<
", size: " << dsize <<
"]:" << std::endl;
4185 std::vector<int> pdata;
4187 for (
uint j = 0; j < dsize; j++) {
4189 std::cout <<
" " << pdata.at(j) << std::endl;
4191 std::cout <<
" ..." << std::endl;
4192 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4193 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4198 std::vector<uint> pdata;
4200 for (
uint j = 0; j < dsize; j++) {
4202 std::cout <<
" " << pdata.at(j) << std::endl;
4204 std::cout <<
" ..." << std::endl;
4205 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4206 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4211 std::vector<float> pdata;
4213 for (
uint j = 0; j < dsize; j++) {
4215 std::cout <<
" " << pdata.at(j) << std::endl;
4217 std::cout <<
" ..." << std::endl;
4218 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4219 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4224 std::vector<double> pdata;
4226 for (
uint j = 0; j < dsize; j++) {
4228 std::cout <<
" " << pdata.at(j) << std::endl;
4230 std::cout <<
" ..." << std::endl;
4231 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4232 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4237 std::vector<vec2> pdata;
4239 for (
uint j = 0; j < dsize; j++) {
4241 std::cout <<
" " << pdata.at(j) << std::endl;
4243 std::cout <<
" ..." << std::endl;
4244 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4245 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4250 std::vector<vec3> pdata;
4252 for (
uint j = 0; j < dsize; j++) {
4254 std::cout <<
" " << pdata.at(j) << std::endl;
4256 std::cout <<
" ..." << std::endl;
4257 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4258 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4263 std::vector<vec4> pdata;
4265 for (
uint j = 0; j < dsize; j++) {
4267 std::cout <<
" " << pdata.at(j) << std::endl;
4269 std::cout <<
" ..." << std::endl;
4270 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4271 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4276 std::vector<int2> pdata;
4278 for (
uint j = 0; j < dsize; j++) {
4280 std::cout <<
" " << pdata.at(j) << std::endl;
4282 std::cout <<
" ..." << std::endl;
4283 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4284 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4289 std::vector<int3> pdata;
4291 for (
uint j = 0; j < dsize; j++) {
4293 std::cout <<
" " << pdata.at(j) << std::endl;
4295 std::cout <<
" ..." << std::endl;
4296 std::cout <<
" " << pdata.at(dsize - 2) << std::endl;
4297 std::cout <<
" " << pdata.at(dsize - 1) << std::endl;
4302 std::vector<int4> pdata;
4304 for (
uint j = 0; j < dsize; j++) {
4306 std::cout <<
" " << pdata.at(j) << std::endl;
4308 std::cout <<
" ..." << std::endl;
4313 std::vector<std::string> pdata;
4315 for (
uint j = 0; j < dsize; j++) {
4317 std::cout <<
" " << pdata.at(j) << std::endl;
4319 std::cout <<
" ..." << std::endl;
4327 std::cout <<
"-------------------------------------------" << std::endl;
4332 if (objects.find(ObjID) == objects.end()) {
4333 helios_runtime_error(
"ERROR (Context::getObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4336 return objects.at(ObjID);
4342 helios_runtime_error(
"ERROR (Context::hideObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4345 objects.at(ObjID)->ishidden =
true;
4346 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4349 helios_runtime_error(
"ERROR (Context::hideObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4352 primitives.at(UUID)->ishidden =
true;
4357 for (
uint ObjID: ObjIDs) {
4365 helios_runtime_error(
"ERROR (Context::showObject): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4368 objects.at(ObjID)->ishidden =
false;
4369 for (
uint UUID: objects.at(ObjID)->getPrimitiveUUIDs()) {
4372 helios_runtime_error(
"ERROR (Context::showObject): Primitive UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
4375 primitives.at(UUID)->ishidden =
false;
4380 for (
uint ObjID: ObjIDs) {
4387 helios_runtime_error(
"ERROR (Context::isObjectHidden): Object ID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4389 return objects.at(ObjID)->ishidden;
4393 return getObjectPointer_private(ObjID)->
getArea();
4398 if (objects.find(ObjID) == objects.end()) {
4399 helios_runtime_error(
"ERROR (Context::getObjectAverageNormal): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4403 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4406 for (
uint UUID: UUIDs) {
4435 for (
uint ObjID: ObjIDs) {
4449 vec3 newN = normalize(new_normal);
4452 float d = std::clamp(oldN * newN, -1.f, 1.f);
4453 float angle = acosf(d);
4457 axis = (std::abs(oldN.
x) < std::abs(oldN.
z)) ?
cross(oldN, {1, 0, 0}) :
cross(oldN, {0, 0, 1});
4469 vec3 localX{1, 0, 0};
4476 vec3 worldX{1, 0, 0};
4477 vec3 targ = worldX - newN * (newN * worldX);
4478 targ = normalize(targ);
4481 float twist = atan2f(newN *
cross(t1, targ),
4495 objects.at(ObjID)->object_origin = origin;
4499 return getObjectPointer_private(ObjID)->
hasTexture();
4503 getObjectPointer_private(ObjID)->
setColor(color);
4507 for (
const uint ObjID: ObjIDs) {
4508 getObjectPointer_private(ObjID)->
setColor(color);
4513 getObjectPointer_private(ObjID)->
setColor(color);
4517 for (
const uint ObjID: ObjIDs) {
4518 getObjectPointer_private(ObjID)->
setColor(color);
4531 for (
uint ObjID: ObjIDs) {
4541 for (
uint ObjID: ObjIDs) {
4547 const std::vector ObjIDs{ObjID};
4553 for (
uint ObjID: ObjIDs) {
4554 if (objects.find(ObjID) == objects.end()) {
4555 helios_runtime_error(
"ERROR (Context::getObjectBoundingBox): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4558 const std::vector<uint> &UUIDs = objects.at(ObjID)->getPrimitiveUUIDs();
4561 for (
const uint UUID: UUIDs) {
4564 if (p == 0 && o == 0) {
4565 min_corner = vertices.front();
4566 max_corner = min_corner;
4571 for (
const vec3 &vert: vertices) {
4572 if (vert.x < min_corner.
x) {
4573 min_corner.
x = vert.x;
4575 if (vert.y < min_corner.
y) {
4576 min_corner.
y = vert.y;
4578 if (vert.z < min_corner.
z) {
4579 min_corner.
z = vert.z;
4581 if (vert.x > max_corner.
x) {
4582 max_corner.
x = vert.x;
4584 if (vert.y > max_corner.
y) {
4585 max_corner.
y = vert.y;
4587 if (vert.z > max_corner.
z) {
4588 max_corner.
z = vert.z;
4597Tile *Context::getTileObjectPointer_private(
uint ObjID)
const {
4599 if (objects.find(ObjID) == objects.end()) {
4600 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4601 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TILE) {
4602 helios_runtime_error(
"ERROR (Context::getTileObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tile Object.");
4605 return dynamic_cast<Tile *
>(objects.at(ObjID));
4608Sphere *Context::getSphereObjectPointer_private(
uint ObjID)
const {
4610 if (objects.find(ObjID) == objects.end()) {
4611 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4612 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_SPHERE) {
4613 helios_runtime_error(
"ERROR (Context::getSphereObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Sphere Object.");
4616 return dynamic_cast<Sphere *
>(objects.at(ObjID));
4619Tube *Context::getTubeObjectPointer_private(
uint ObjID)
const {
4621 if (objects.find(ObjID) == objects.end()) {
4622 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4623 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_TUBE) {
4624 helios_runtime_error(
"ERROR (Context::getTubeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Tube Object.");
4627 return dynamic_cast<Tube *
>(objects.at(ObjID));
4630Box *Context::getBoxObjectPointer_private(
uint ObjID)
const {
4632 if (objects.find(ObjID) == objects.end()) {
4633 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4634 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_BOX) {
4635 helios_runtime_error(
"ERROR (Context::getBoxObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Box Object.");
4638 return dynamic_cast<Box *
>(objects.at(ObjID));
4641Disk *Context::getDiskObjectPointer_private(
uint ObjID)
const {
4643 if (objects.find(ObjID) == objects.end()) {
4644 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4645 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_DISK) {
4646 helios_runtime_error(
"ERROR (Context::getDiskObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Disk Object.");
4649 return dynamic_cast<Disk *
>(objects.at(ObjID));
4652Polymesh *Context::getPolymeshObjectPointer_private(
uint ObjID)
const {
4654 if (objects.find(ObjID) == objects.end()) {
4655 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4656 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_POLYMESH) {
4657 helios_runtime_error(
"ERROR (Context::getPolymeshObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Polymesh Object.");
4660 return dynamic_cast<Polymesh *
>(objects.at(ObjID));
4663Cone *Context::getConeObjectPointer_private(
uint ObjID)
const {
4665 if (objects.find(ObjID) == objects.end()) {
4666 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4667 }
else if (objects.at(ObjID)->getObjectType() != OBJECT_TYPE_CONE) {
4668 helios_runtime_error(
"ERROR (Context::getConeObjectPointer): ObjectID of " + std::to_string(ObjID) +
" is not a Cone Object.");
4671 return dynamic_cast<Cone *
>(objects.at(ObjID));
4675 return getTileObjectPointer_private(ObjID)->
getCenter();
4679 return getTileObjectPointer_private(ObjID)->
getSize();
4687 return getTileObjectPointer_private(ObjID)->
getNormal();
4691 return getTileObjectPointer_private(ObjID)->
getTextureUV();
4695 return getTileObjectPointer_private(ObjID)->
getVertices();
4699 return getSphereObjectPointer_private(ObjID)->
getCenter();
4703 return getSphereObjectPointer_private(ObjID)->
getRadius();
4711 return getSphereObjectPointer_private(ObjID)->
getVolume();
4719 return getTubeObjectPointer_private(ObjID)->
getNodes();
4723 return getTubeObjectPointer_private(ObjID)->
getNodeCount();
4727 return getTubeObjectPointer_private(ObjID)->
getNodeRadii();
4731 return getTubeObjectPointer_private(ObjID)->
getNodeColors();
4735 return getTubeObjectPointer_private(ObjID)->
getVolume();
4739 return getTubeObjectPointer_private(ObjID)->
getSegmentVolume(segment_index);
4744 if (objects.find(ObjID) == objects.end()) {
4745 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4753 if (objects.find(ObjID) == objects.end()) {
4754 helios_runtime_error(
"ERROR (Context::appendTubeSegment): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4757 dynamic_cast<Tube *
>(objects.at(ObjID))->
appendTubeSegment(node_position, node_radius, texturefile, textureuv_ufrac);
4762 if (objects.find(ObjID) == objects.end()) {
4763 helios_runtime_error(
"ERROR (Context::scaleTubeGirth): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4771 if (objects.find(ObjID) == objects.end()) {
4772 helios_runtime_error(
"ERROR (Context::setTubeRadii): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4780 if (objects.find(ObjID) == objects.end()) {
4781 helios_runtime_error(
"ERROR (Context::scaleTubeLength): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4789 if (objects.find(ObjID) == objects.end()) {
4790 helios_runtime_error(
"ERROR (Context::pruneTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4798 if (objects.find(ObjID) == objects.end()) {
4799 helios_runtime_error(
"ERROR (Context::setTubeNodes): ObjectID of " + std::to_string(ObjID) +
" does not exist in the Context.");
4806 return getBoxObjectPointer_private(ObjID)->
getCenter();
4810 return getBoxObjectPointer_private(ObjID)->
getSize();
4818 return getBoxObjectPointer_private(ObjID)->
getVolume();
4822 return getDiskObjectPointer_private(ObjID)->
getCenter();
4826 return getDiskObjectPointer_private(ObjID)->
getSize();
4842 return getConeObjectPointer_private(ObjID)->
getNodeRadii();
4850 return getConeObjectPointer_private(ObjID)->
getNodeRadius(number);
4858 return getConeObjectPointer_private(ObjID)->
getLength();
4862 return getConeObjectPointer_private(ObjID)->
getVolume();
4866 getConeObjectPointer_private(ObjID)->
scaleLength(scale_factor);
4870 getConeObjectPointer_private(ObjID)->
scaleGirth(scale_factor);
4874 return getPolymeshObjectPointer_private(ObjID)->
getVolume();
4878 api_warnings.
report(std::cerr);