114 if (!validateTextureFileExtenstion(texturefile)) {
115 helios_runtime_error(
"ERROR (Context::addSphereObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
116 }
else if (!doesTextureFileExist(texturefile)) {
117 helios_runtime_error(
"ERROR (Context::addSphereObject): Texture file " + std::string(texturefile) +
" does not exist.");
118 }
else if (radius.
x <= 0.f || radius.
y <= 0.f || radius.
z <= 0.f) {
122 std::vector<uint> UUID;
123 UUID.reserve(Ndivs * (Ndivs - 2) * 2 + 2 * Ndivs);
125 float dtheta =
PI_F / float(Ndivs);
126 float dphi = 2.0f *
PI_F / float(Ndivs);
131 for (
int j = 0; j < Ndivs; j++) {
139 vec3 n0 = v0 - center;
141 vec3 n1 = v1 - center;
143 vec3 n2 = v2 - center;
146 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);
147 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);
148 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);
150 if (j == Ndivs - 1) {
154 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
156 UUID.push_back(triangle_uuid);
163 for (
int j = 0; j < Ndivs; j++) {
172 vec3 n0 = v0 - center;
174 vec3 n1 = v1 - center;
176 vec3 n2 = v2 - center;
179 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);
180 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);
181 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);
183 if (j == Ndivs - 1) {
187 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
189 UUID.push_back(triangle_uuid);
196 for (
int j = 0; j < Ndivs; j++) {
197 for (
int i = 1; i < Ndivs - 1; i++) {
207 vec3 n0 = v0 - center;
209 vec3 n1 = v1 - center;
211 vec3 n2 = v2 - center;
213 vec3 n3 = v3 - center;
216 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);
217 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);
218 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);
219 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);
221 if (j == Ndivs - 1) {
226 uint triangle_uuid1 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
228 UUID.push_back(triangle_uuid1);
233 uint triangle_uuid2 =
addTriangle(v0, v2, v3, texturefile, uv0, uv2, uv3);
235 UUID.push_back(triangle_uuid2);
242 auto *sphere_new = (
new Sphere(currentObjectID, UUID, Ndivs, texturefile,
this));
244 float T[16], transform[16];
245 sphere_new->getTransformationMatrix(transform);
248 matmult(T, transform, transform);
251 matmult(T, transform, transform);
252 sphere_new->setTransformationMatrix(transform);
255 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
258 objects[currentObjectID] = sphere_new;
261 return currentObjectID - 1;
271 if (size.
x == 0 || size.
y == 0) {
273 }
else if (subdiv.
x < 1 || subdiv.
y < 1) {
274 helios_runtime_error(
"ERROR (Context::addTileObject): Number of tile subdivisions must be greater than 0.");
277 std::vector<uint> UUID;
278 UUID.reserve(subdiv.
x * subdiv.
y);
281 subsize.
x = size.
x / float(subdiv.
x);
282 subsize.
y = size.
y / float(subdiv.
y);
284 for (
uint j = 0; j < subdiv.
y; j++) {
285 for (
uint i = 0; i < subdiv.
x; i++) {
286 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);
291 getPrimitivePointer_private(UUID.back())->rotate(-rotation.
elevation,
"x");
294 getPrimitivePointer_private(UUID.back())->rotate(-rotation.
azimuth,
"z");
296 getPrimitivePointer_private(UUID.back())->translate(center);
300 auto *tile_new = (
new Tile(currentObjectID, UUID, subdiv,
"",
this));
302 float T[16], S[16],
R[16];
305 tile_new->getTransformationMatrix(transform);
308 matmult(S, transform, transform);
316 matmult(T, transform, transform);
317 tile_new->setTransformationMatrix(transform);
319 tile_new->setColor(color);
322 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
325 tile_new->object_origin = center;
327 objects[currentObjectID] = tile_new;
329 return currentObjectID - 1;
337 if (!validateTextureFileExtenstion(texturefile)) {
338 helios_runtime_error(
"ERROR (Context::addTileObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
339 }
else if (!doesTextureFileExist(texturefile)) {
340 helios_runtime_error(
"ERROR (Context::addTileObject): Texture file " + std::string(texturefile) +
" does not exist.");
341 }
else if (size.
x == 0 || size.
y == 0) {
343 }
else if (subdiv.
x < 1 || subdiv.
y < 1) {
344 helios_runtime_error(
"ERROR (Context::addTileObject): Number of tile subdivisions must be greater than 0.");
345 }
else if (texture_repeat.
x < 1 || texture_repeat.
y < 1) {
346 helios_runtime_error(
"ERROR (Context::addTileObject): Number of texture repeats must be greater than 0.");
350 int2 repeat = texture_repeat;
351 repeat.
x = std::min(subdiv.
x, repeat.
x);
352 repeat.
y = std::min(subdiv.
y, repeat.
y);
353 while (subdiv.
x % repeat.
x != 0) {
356 while (subdiv.
y % repeat.
y != 0) {
360 std::vector<uint> UUID;
361 UUID.reserve(subdiv.
x * subdiv.
y);
364 subsize.
x = size.
x / float(subdiv.
x);
365 subsize.
y = size.
y / float(subdiv.
y);
367 std::vector<helios::vec2> uv(4);
369 sub_per_repeat.
x = subdiv.
x / repeat.
x;
370 sub_per_repeat.
y = subdiv.
y / repeat.
y;
372 uv_sub.
x = 1.f / float(sub_per_repeat.
x);
373 uv_sub.
y = 1.f / float(sub_per_repeat.
y);
375 addTexture(texturefile);
377 const int2 &sz = textures.at(texturefile).getImageResolution();
378 if (subdiv.
x >= repeat.
x * sz.
x || subdiv.
y >= repeat.
y * sz.
y) {
379 helios_runtime_error(
"ERROR (Context::addTileObject): The resolution of the texture image '" + std::string(texturefile) +
"' is lower than the number of tile subdivisions. Increase resolution of the texture image.");
382 for (
uint j = 0; j < subdiv.
y; j++) {
383 for (
uint i = 0; i < subdiv.
x; i++) {
384 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);
386 uint i_local = i % sub_per_repeat.
x;
387 uint j_local = j % sub_per_repeat.
y;
388 uv.at(0) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local) * uv_sub.
y);
389 uv.at(1) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local) * uv_sub.
y);
390 uv.at(2) =
make_vec2(
float(i_local + 1) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
391 uv.at(3) =
make_vec2(
float(i_local) * uv_sub.
x,
float(j_local + 1) * uv_sub.
y);
393 auto *patch_new = (
new Patch(texturefile, uv, textures, 0, currentUUID));
401 assert(size.
x > 0.f && size.
y > 0.f);
402 patch_new->scale(
make_vec3(subsize.
x, subsize.
y, 1));
404 patch_new->translate(subcenter);
407 patch_new->rotate(-rotation.
elevation,
"x");
410 patch_new->rotate(-rotation.
azimuth,
"z");
413 patch_new->translate(center);
415 primitives[currentUUID] = patch_new;
417 UUID.push_back(currentUUID - 1);
421 auto *tile_new = (
new Tile(currentObjectID, UUID, subdiv, texturefile,
this));
423 float T[16], S[16],
R[16];
426 tile_new->getTransformationMatrix(transform);
429 matmult(S, transform, transform);
437 matmult(T, transform, transform);
438 tile_new->setTransformationMatrix(transform);
441 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
444 tile_new->object_origin = center;
446 objects[currentObjectID] = tile_new;
448 return currentObjectID - 1;
464 const uint node_count = nodes.size();
466 if (node_count == 0) {
468 }
else if (node_count != radius.size()) {
469 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `radius' arguments must agree.");
470 }
else if (node_count != color.size()) {
471 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `color' arguments must agree.");
475 std::vector<float> cfact(radial_subdivisions + 1);
476 std::vector<float> sfact(radial_subdivisions + 1);
477 std::vector<std::vector<vec3>> triangle_vertices;
478 resize_vector(triangle_vertices, radial_subdivisions + 1, node_count);
481 for (
int j = 0; j < radial_subdivisions + 1; j++) {
482 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
483 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
486 vec3 initial_radial(1.0f, 0.0f, 0.0f);
487 vec3 previous_axial_vector;
488 vec3 previous_radial_dir;
490 for (
int i = 0; i < node_count; i++) {
491 if (radius.at(i) < 0) {
496 axial_vector = nodes[i + 1] - nodes[i];
501 axial_vector = axial_vector / mag;
503 if (fabs(axial_vector * initial_radial) > 0.95f) {
504 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
507 if (fabs(axial_vector.
z) > 0.95f) {
508 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
510 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
512 if (i == node_count - 1) {
513 axial_vector = nodes[i] - nodes[i - 1];
515 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
521 axial_vector = axial_vector / mag;
525 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
527 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
531 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
532 if (fabs(axial_vector * fallback_radial) > 0.95f) {
533 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
535 if (fabs(axial_vector.
z) > 0.95f) {
536 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
538 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
542 previous_axial_vector = axial_vector;
544 vec3 radial_dir = previous_radial_dir;
545 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
548 for (
int j = 0; j < radial_subdivisions + 1; j++) {
549 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
550 triangle_vertices[i][j] = nodes[i] + normal;
555 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
559 for (
int j = 0; j < radial_subdivisions; j++) {
560 for (
int i = 0; i < node_count - 1; i++) {
561 v0 = triangle_vertices[i][j];
562 v1 = triangle_vertices[i + 1][j + 1];
563 v2 = triangle_vertices[i][j + 1];
565 UUIDs.at(ii) =
addTriangle(v0, v1, v2, color.at(i));
567 v0 = triangle_vertices[i][j];
568 v1 = triangle_vertices[i + 1][j];
569 v2 = triangle_vertices[i + 1][j + 1];
571 UUIDs.at(ii + 1) =
addTriangle(v0, v1, v2, color.at(i));
577 auto *tube_new = (
new Tube(currentObjectID, UUIDs, nodes, radius, color, triangle_vertices, radial_subdivisions,
"",
this));
579 for (
uint p: UUIDs) {
580 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
583 objects[currentObjectID] = tube_new;
586 uint objID = currentObjectID - 1;
602uint Context::addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile,
const std::vector<float> &textureuv_ufrac) {
603 if (!validateTextureFileExtenstion(texturefile)) {
604 helios_runtime_error(
"ERROR (Context::addTubeObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
605 }
else if (!doesTextureFileExist(texturefile)) {
606 helios_runtime_error(
"ERROR (Context::addTubeObject): Texture file " + std::string(texturefile) +
" does not exist.");
609 const uint node_count = nodes.size();
611 if (node_count == 0) {
613 }
else if (node_count != radius.size()) {
614 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `radius' arguments must agree.");
615 }
else if (node_count != textureuv_ufrac.size()) {
616 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `textureuv_ufrac' arguments must agree.");
620 std::vector<float> cfact(radial_subdivisions + 1);
621 std::vector<float> sfact(radial_subdivisions + 1);
622 std::vector<std::vector<vec3>> triangle_vertices;
623 resize_vector(triangle_vertices, radial_subdivisions + 1, node_count);
624 std::vector<std::vector<vec2>> uv;
628 for (
int j = 0; j < radial_subdivisions + 1; j++) {
629 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
630 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
633 vec3 initial_radial(1.0f, 0.0f, 0.0f);
634 vec3 previous_axial_vector;
635 vec3 previous_radial_dir;
637 for (
int i = 0; i < node_count; i++) {
638 if (radius.at(i) < 0) {
643 axial_vector = nodes[i + 1] - nodes[i];
648 axial_vector = axial_vector / mag;
650 if (fabs(axial_vector * initial_radial) > 0.95f) {
651 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
654 if (fabs(axial_vector.
z) > 0.95f) {
655 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
657 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
659 if (i == node_count - 1) {
660 axial_vector = nodes[i] - nodes[i - 1];
662 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
668 axial_vector = axial_vector / mag;
672 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
674 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
678 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
679 if (fabs(axial_vector * fallback_radial) > 0.95f) {
680 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
682 if (fabs(axial_vector.
z) > 0.95f) {
683 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
685 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
689 previous_axial_vector = axial_vector;
691 vec3 radial_dir = previous_radial_dir;
692 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
695 for (
int j = 0; j < radial_subdivisions + 1; j++) {
696 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
697 triangle_vertices[i][j] = nodes[i] + normal;
699 uv[i][j].
x = textureuv_ufrac[i];
700 uv[i][j].y = float(j) / float(radial_subdivisions);
704 std::vector<uint> UUIDs;
705 UUIDs.reserve(2 * (node_count - 1) * radial_subdivisions);
708 for (
int j = 0; j < radial_subdivisions; j++) {
709 for (
int i = 0; i < node_count - 1; i++) {
710 v0 = triangle_vertices[i][j];
711 v1 = triangle_vertices[i + 1][j + 1];
712 v2 = triangle_vertices[i][j + 1];
715 uv1 = uv[i + 1][j + 1];
718 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
720 UUIDs.push_back(triangle_uuid);
725 v0 = triangle_vertices[i][j];
726 v1 = triangle_vertices[i + 1][j];
727 v2 = triangle_vertices[i + 1][j + 1];
731 uv2 = uv[i + 1][j + 1];
733 uint triangle_uuid2 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
735 UUIDs.push_back(triangle_uuid2);
742 std::vector<RGBcolor> colors(nodes.size());
744 auto *tube_new = (
new Tube(currentObjectID, UUIDs, nodes, radius, colors, triangle_vertices, radial_subdivisions, texturefile,
this));
746 for (
uint p: UUIDs) {
747 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
750 objects[currentObjectID] = tube_new;
753 uint objID = currentObjectID - 1;
774 if (size.
x <= 0 || size.
y <= 0 || size.
z <= 0) {
776 }
else if (subdiv.
x < 1 || subdiv.
y < 1 || subdiv.
z < 1) {
777 helios_runtime_error(
"ERROR (Context::addBoxObject): Number of box subdivisions must be positive.");
780 std::vector<uint> UUID;
781 UUID.reserve(2 * (subdiv.
z * (subdiv.
x + subdiv.
y) + subdiv.
x * subdiv.
y));
784 subsize.
x = size.
x / float(subdiv.
x);
785 subsize.
y = size.
y / float(subdiv.
y);
786 subsize.
z = size.
z / float(subdiv.
z);
789 std::vector<uint> U, U_copy;
791 if (reverse_normals) {
796 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
798 UUID.insert(UUID.end(), U.begin(), U.end());
801 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
803 UUID.insert(UUID.end(), U.begin(), U.end());
808 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
810 UUID.insert(UUID.end(), U.begin(), U.end());
813 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
815 UUID.insert(UUID.end(), U.begin(), U.end());
820 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
822 UUID.insert(UUID.end(), U.begin(), U.end());
825 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
827 UUID.insert(UUID.end(), U.begin(), U.end());
833 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
835 UUID.insert(UUID.end(), U.begin(), U.end());
838 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
840 UUID.insert(UUID.end(), U.begin(), U.end());
845 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
847 UUID.insert(UUID.end(), U.begin(), U.end());
850 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
852 UUID.insert(UUID.end(), U.begin(), U.end());
857 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
859 UUID.insert(UUID.end(), U.begin(), U.end());
862 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
864 UUID.insert(UUID.end(), U.begin(), U.end());
867 auto *box_new = (
new Box(currentObjectID, UUID, subdiv,
"",
this));
869 float T[16], transform[16];
870 box_new->getTransformationMatrix(transform);
873 matmult(T, transform, transform);
876 matmult(T, transform, transform);
877 box_new->setTransformationMatrix(transform);
879 box_new->setColor(color);
882 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
885 box_new->object_origin = center;
887 objects[currentObjectID] = box_new;
889 return currentObjectID - 1;
893 if (!validateTextureFileExtenstion(texturefile)) {
894 helios_runtime_error(
"ERROR (Context::addBoxObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
895 }
else if (!doesTextureFileExist(texturefile)) {
896 helios_runtime_error(
"ERROR (Context::addBoxObject): Texture file " + std::string(texturefile) +
" does not exist.");
899 std::vector<uint> UUID;
902 subsize.
x = size.
x / float(subdiv.
x);
903 subsize.
y = size.
y / float(subdiv.
y);
904 subsize.
z = size.
z / float(subdiv.
z);
907 std::vector<uint> U, U_copy;
909 if (reverse_normals) {
914 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
916 UUID.insert(UUID.end(), U.begin(), U.end());
919 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
921 UUID.insert(UUID.end(), U.begin(), U.end());
926 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
928 UUID.insert(UUID.end(), U.begin(), U.end());
931 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
933 UUID.insert(UUID.end(), U.begin(), U.end());
938 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
940 UUID.insert(UUID.end(), U.begin(), U.end());
943 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
945 UUID.insert(UUID.end(), U.begin(), U.end());
951 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
953 UUID.insert(UUID.end(), U.begin(), U.end());
956 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
958 UUID.insert(UUID.end(), U.begin(), U.end());
963 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
965 UUID.insert(UUID.end(), U.begin(), U.end());
968 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
970 UUID.insert(UUID.end(), U.begin(), U.end());
975 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
977 UUID.insert(UUID.end(), U.begin(), U.end());
980 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
982 UUID.insert(UUID.end(), U.begin(), U.end());
985 auto *box_new = (
new Box(currentObjectID, UUID, subdiv, texturefile,
this));
987 float T[16], transform[16];
988 box_new->getTransformationMatrix(transform);
991 matmult(T, transform, transform);
994 matmult(T, transform, transform);
995 box_new->setTransformationMatrix(transform);
998 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1001 box_new->object_origin = center;
1003 objects[currentObjectID] = box_new;
1005 return currentObjectID - 1;
1033 std::vector<uint> UUID(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
1036 for (
int r = 0; r < Ndivs.
y; r++) {
1037 for (
int t = 0; t < Ndivs.
x; t++) {
1038 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
1039 float theta = dtheta * float(t);
1040 float theta_plus = dtheta * float(t + 1);
1042 float rx = size.
x / float(Ndivs.
y) * float(r);
1043 float ry = size.
y / float(Ndivs.
y) * float(r);
1045 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
1046 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
1051 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);
1053 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);
1055 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
elevation,
"y");
1056 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
azimuth,
"z");
1057 getPrimitivePointer_private(UUID.at(i))->translate(center);
1063 auto *disk_new = (
new Disk(currentObjectID, UUID, Ndivs,
"",
this));
1065 float T[16], transform[16];
1066 disk_new->getTransformationMatrix(transform);
1069 matmult(T, transform, transform);
1072 matmult(T, transform, transform);
1073 disk_new->setTransformationMatrix(transform);
1075 disk_new->setColor(color);
1077 for (
uint p: UUID) {
1078 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1081 disk_new->object_origin = center;
1083 objects[currentObjectID] = disk_new;
1085 return currentObjectID - 1;
1089 if (!validateTextureFileExtenstion(texturefile)) {
1090 helios_runtime_error(
"ERROR (Context::addDiskObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1091 }
else if (!doesTextureFileExist(texturefile)) {
1092 helios_runtime_error(
"ERROR (Context::addDiskObject): Texture file " + std::string(texturefile) +
" does not exist.");
1095 std::vector<uint> UUID;
1096 UUID.reserve(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
1097 for (
int r = 0; r < Ndivs.
y; r++) {
1098 for (
int t = 0; t < Ndivs.
x; t++) {
1099 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
1100 float theta = dtheta * float(t);
1101 float theta_plus = dtheta * float(t + 1);
1103 float rx = size.
x / float(Ndivs.
y) * float(r);
1104 float ry = size.
y / float(Ndivs.
y) * float(r);
1105 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
1106 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
1109 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),
1110 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
1111 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
1113 UUID.push_back(triangle_uuid);
1119 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,
1120 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)),
1121 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)));
1123 UUID.push_back(triangle_uuid1);
1128 uint triangle_uuid2 =
1129 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,
1130 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)),
1131 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
1133 UUID.push_back(triangle_uuid2);
1140 size_t start_idx = UUID.size() - (r == 0 ? 1 : 2);
1141 for (
size_t uuid_idx = start_idx; uuid_idx < UUID.size(); uuid_idx++) {
1142 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
elevation,
"y");
1143 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
azimuth,
"z");
1144 getPrimitivePointer_private(UUID.at(uuid_idx))->translate(center);
1149 auto *disk_new = (
new Disk(currentObjectID, UUID, Ndivs, texturefile,
this));
1151 float T[16], transform[16];
1152 disk_new->getTransformationMatrix(transform);
1155 matmult(T, transform, transform);
1158 matmult(T, transform, transform);
1159 disk_new->setTransformationMatrix(transform);
1161 for (
uint p: UUID) {
1162 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1165 disk_new->object_origin = center;
1167 objects[currentObjectID] = disk_new;
1169 return currentObjectID - 1;
1173 if (UUIDs.empty()) {
1174 helios_runtime_error(
"ERROR (Context::addPolymeshObject): UUIDs array is empty. Cannot create polymesh object.");
1176 helios_runtime_error(
"ERROR (Context::addPolymeshObject): One or more of the provided UUIDs does not exist. Cannot create polymesh object.");
1180 std::vector<uint> UUIDs_polymesh;
1181 UUIDs_polymesh.reserve(UUIDs.size());
1182 size_t skipped_UUIDs = 0;
1183 for (
uint UUID: UUIDs) {
1184 if (getPrimitivePointer_private(UUID)->getParentObjectID() != 0) {
1187 UUIDs_polymesh.push_back(UUID);
1190 if (skipped_UUIDs > 0) {
1191 std::cerr <<
"WARNING (Context::addPolymeshObject): " << skipped_UUIDs <<
" primitives were not added to polymesh object because they already belong to another object." << std::endl;
1194 auto *polymesh_new = (
new Polymesh(currentObjectID, UUIDs_polymesh,
"",
this));
1196 float T[16], transform[16];
1197 polymesh_new->getTransformationMatrix(transform);
1199 makeTranslationMatrix(getPrimitivePointer_private(UUIDs_polymesh.front())->getVertices().front(), T);
1200 matmult(T, transform, transform);
1201 polymesh_new->setTransformationMatrix(transform);
1203 for (
uint UUID: UUIDs_polymesh) {
1204 getPrimitivePointer_private(UUID)->setParentObjectID(currentObjectID);
1207 objects[currentObjectID] = polymesh_new;
1210 uint objID = currentObjectID - 1;
1222 const std::vector nodes{node0, node1};
1223 const std::vector radii{radius0, radius1};
1226 std::vector<float> cfact(Ndivs + 1);
1227 std::vector<float> sfact(Ndivs + 1);
1228 std::vector<std::vector<vec3>> xyz(Ndivs + 1);
1229 std::vector<std::vector<vec3>> normal(Ndivs + 1);
1231 for (
uint j = 0; j < Ndivs + 1; j++) {
1232 xyz.at(j).resize(2);
1233 normal.at(j).resize(2);
1235 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
1237 for (
int j = 0; j < Ndivs + 1; j++) {
1238 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
1239 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
1242 for (
int i = 0; i < 2; i++) {
1247 vec.
x = nodes[i + 1].x - nodes[i].x;
1248 vec.
y = nodes[i + 1].y - nodes[i].y;
1249 vec.
z = nodes[i + 1].z - nodes[i].z;
1250 }
else if (i == 1) {
1251 vec.
x = nodes[i].x - nodes[i - 1].x;
1252 vec.
y = nodes[i].y - nodes[i - 1].y;
1253 vec.
z = nodes[i].z - nodes[i - 1].z;
1260 convec =
cross(nvec, vec);
1264 norm = std::max(convec.
magnitude(), 1e-6f);
1266 convec = convec / norm;
1267 nvec =
cross(vec, convec);
1270 nvec =
cross(convec, vec);
1271 norm = std::max(nvec.
magnitude(), 1e-6f);
1275 for (
int j = 0; j < Ndivs + 1; j++) {
1276 normal[j][i].
x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
1277 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
1278 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
1280 xyz[j][i].x = nodes[i].x + normal[j][i].x;
1281 xyz[j][i].y = nodes[i].y + normal[j][i].y;
1282 xyz[j][i].z = nodes[i].z + normal[j][i].z;
1284 normal[j][i] = normal[j][i] / radii[i];
1289 std::vector<uint> UUID(2 * Ndivs);
1292 for (
int j = 0; j < Ndivs; j++) {
1308 auto *cone_new = (
new Cone(currentObjectID, UUID, node0, node1, radius0, radius1, Ndivs,
"",
this));
1310 for (
uint p: UUID) {
1311 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1314 cone_new->setColor(color);
1316 objects[currentObjectID] = cone_new;
1319 uint objID = currentObjectID - 1;
1326 if (!validateTextureFileExtenstion(texturefile)) {
1327 helios_runtime_error(
"ERROR (Context::addConeObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1328 }
else if (!doesTextureFileExist(texturefile)) {
1329 helios_runtime_error(
"ERROR (Context::addConeObject): Texture file " + std::string(texturefile) +
" does not exist.");
1332 const std::vector<helios::vec3> nodes{node0, node1};
1333 const std::vector<float> radii{radius0, radius1};
1336 std::vector<float> cfact(Ndivs + 1);
1337 std::vector<float> sfact(Ndivs + 1);
1338 std::vector<std::vector<vec3>> xyz, normal;
1339 std::vector<std::vector<vec2>> uv;
1340 xyz.resize(Ndivs + 1);
1341 normal.resize(Ndivs + 1);
1342 uv.resize(Ndivs + 1);
1343 for (
uint j = 0; j < Ndivs + 1; j++) {
1344 xyz.at(j).resize(2);
1345 normal.at(j).resize(2);
1348 vec3 nvec(0.f, 1.f, 0.f);
1350 for (
int j = 0; j < Ndivs + 1; j++) {
1351 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
1352 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
1355 for (
int i = 0; i < 2; i++) {
1360 vec.
x = nodes[i + 1].x - nodes[i].x;
1361 vec.
y = nodes[i + 1].y - nodes[i].y;
1362 vec.
z = nodes[i + 1].z - nodes[i].z;
1363 }
else if (i == 1) {
1364 vec.
x = nodes[i].x - nodes[i - 1].x;
1365 vec.
y = nodes[i].y - nodes[i - 1].y;
1366 vec.
z = nodes[i].z - nodes[i - 1].z;
1373 convec =
cross(nvec, vec);
1377 norm = std::max(convec.
magnitude(), 1e-6f);
1379 convec = convec / norm;
1380 nvec =
cross(vec, convec);
1383 nvec =
cross(convec, vec);
1384 norm = std::max(nvec.
magnitude(), 1e-6f);
1388 for (
int j = 0; j < Ndivs + 1; j++) {
1389 normal[j][i].
x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
1390 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
1391 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
1393 xyz[j][i].x = nodes[i].x + normal[j][i].x;
1394 xyz[j][i].y = nodes[i].y + normal[j][i].y;
1395 xyz[j][i].z = nodes[i].z + normal[j][i].z;
1397 uv[j][i].x = float(i) / float(2 - 1);
1398 uv[j][i].y = float(j) / float(Ndivs);
1400 normal[j][i] = normal[j][i] / radii[i];
1406 std::vector<uint> UUID;
1408 for (
int i = 0; i < 2 - 1; i++) {
1409 for (
int j = 0; j < Ndivs; j++) {
1411 v1 = xyz[j + 1][i + 1];
1415 uv1 = uv[j + 1][i + 1];
1418 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
1419 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1421 UUID.push_back(triangle_uuid);
1429 v2 = xyz[j + 1][i + 1];
1433 uv2 = uv[j + 1][i + 1];
1435 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
1436 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1438 UUID.push_back(triangle_uuid);
1446 auto *cone_new = (
new Cone(currentObjectID, UUID, node0, node1, radius0, radius1, Ndivs, texturefile,
this));
1448 for (
uint p: UUID) {
1449 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1452 objects[currentObjectID] = cone_new;
1455 uint objID = currentObjectID - 1;
1876Tube::Tube(
uint a_OID,
const std::vector<uint> &a_UUIDs,
const std::vector<vec3> &a_nodes,
const std::vector<float> &a_radius,
const std::vector<helios::RGBcolor> &a_colors,
const std::vector<std::vector<helios::vec3>> &a_triangle_vertices,
1982 if (node_radius < 0) {
1985 node_radius = std::max((
float) 1e-5, node_radius);
1987 uint radial_subdivisions = subdiv;
1990 std::vector<float> cfact(radial_subdivisions + 1);
1991 std::vector<float> sfact(radial_subdivisions + 1);
1993 for (
int j = 0; j < radial_subdivisions + 1; j++) {
1994 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
1995 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
1998 triangle_vertices.resize(triangle_vertices.size() + 1);
1999 triangle_vertices.back().resize(radial_subdivisions + 1);
2001 nodes.push_back(node_position);
2002 radius.push_back(node_radius);
2003 colors.push_back(node_color);
2005 int node_count = nodes.size();
2007 vec3 initial_radial(1.0f, 0.0f, 0.0f);
2008 vec3 previous_axial_vector;
2009 vec3 previous_radial_dir;
2011 for (
int i = 0; i < node_count; i++) {
2012 if (radius.at(i) < 0) {
2017 axial_vector = nodes[i + 1] - nodes[i];
2022 axial_vector = axial_vector / mag;
2024 if (fabs(axial_vector * initial_radial) > 0.95f) {
2025 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
2028 if (fabs(axial_vector.
z) > 0.95f) {
2029 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
2031 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
2033 if (i == node_count - 1) {
2034 axial_vector = nodes[i] - nodes[i - 1];
2036 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
2042 axial_vector = axial_vector / mag;
2046 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
2048 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
2052 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2053 if (fabs(axial_vector * fallback_radial) > 0.95f) {
2054 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
2056 if (fabs(axial_vector.
z) > 0.95f) {
2057 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2059 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
2073 previous_axial_vector = axial_vector;
2075 vec3 radial_dir = previous_radial_dir;
2076 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
2079 if (i < node_count - 2) {
2083 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2084 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
2085 triangle_vertices[i][j] = nodes[i] + normal;
2091 for (
int j = 0; j < radial_subdivisions; j++) {
2092 vec3 v0 = triangle_vertices.at(1).at(j);
2093 vec3 v1 = triangle_vertices.at(1 + 1).at(j + 1);
2094 vec3 v2 = triangle_vertices.at(1).at(j + 1);
2096 UUIDs.push_back(context->addTriangle(v0, v1, v2, node_color));
2098 v0 = triangle_vertices.at(1).at(j);
2099 v1 = triangle_vertices.at(1 + 1).at(j);
2100 v2 = triangle_vertices.at(1 + 1).at(j + 1);
2102 UUIDs.push_back(context->addTriangle(v0, v1, v2, node_color));
2105 for (
uint p: UUIDs) {
2106 context->setPrimitiveParentObjectID(p, this->OID);
2109 updateTriangleVertices();
2115 if (node_radius < 0) {
2117 }
else if (textureuv_ufrac.
x < 0 || textureuv_ufrac.
y < 0 || textureuv_ufrac.
x > 1 || textureuv_ufrac.
y > 1) {
2118 helios_runtime_error(
"ERROR (Tube::appendTubeSegment): Texture U fraction must be between 0 and 1.");
2120 node_radius = std::max((
float) 1e-5, node_radius);
2122 uint radial_subdivisions = subdiv;
2125 std::vector<float> cfact(radial_subdivisions + 1);
2126 std::vector<float> sfact(radial_subdivisions + 1);
2128 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2129 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2130 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2133 triangle_vertices.resize(triangle_vertices.size() + 1);
2134 triangle_vertices.back().resize(radial_subdivisions + 1);
2135 std::vector<std::vector<vec2>> uv;
2138 nodes.push_back(node_position);
2139 radius.push_back(node_radius);
2140 colors.push_back(RGB::black);
2142 int node_count = nodes.size();
2144 vec3 initial_radial(1.0f, 0.0f, 0.0f);
2145 vec3 previous_axial_vector;
2146 vec3 previous_radial_dir;
2148 for (
int i = 0; i < node_count; i++) {
2149 if (radius.at(i) < 0) {
2154 axial_vector = nodes[i + 1] - nodes[i];
2159 axial_vector = axial_vector / mag;
2161 if (fabs(axial_vector * initial_radial) > 0.95f) {
2162 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
2165 if (fabs(axial_vector.
z) > 0.95f) {
2166 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
2168 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
2170 if (i == node_count - 1) {
2171 axial_vector = nodes[i] - nodes[i - 1];
2173 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
2179 axial_vector = axial_vector / mag;
2183 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
2185 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
2189 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2190 if (fabs(axial_vector * fallback_radial) > 0.95f) {
2191 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
2193 if (fabs(axial_vector.
z) > 0.95f) {
2194 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2196 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
2200 previous_axial_vector = axial_vector;
2202 vec3 radial_dir = previous_radial_dir;
2203 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
2206 if (i < node_count - 2) {
2210 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2211 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
2212 triangle_vertices[i][j] = nodes[i] + normal;
2216 std::vector<float> ufrac{textureuv_ufrac.
x, textureuv_ufrac.
y};
2217 for (
int i = 0; i < 2; i++) {
2218 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2219 uv[i][j].x = ufrac[i];
2220 uv[i][j].y = float(j) / float(radial_subdivisions);
2224 int old_triangle_count = UUIDs.size();
2230 for (
int j = 0; j < radial_subdivisions; j++) {
2231 v0 = triangle_vertices[node_count - 2][j];
2232 v1 = triangle_vertices[node_count - 1][j + 1];
2233 v2 = triangle_vertices[node_count - 2][j + 1];
2239 UUIDs.push_back(context->addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2));
2241 v0 = triangle_vertices[node_count - 2][j];
2242 v1 = triangle_vertices[node_count - 1][j];
2243 v2 = triangle_vertices[node_count - 1][j + 1];
2249 UUIDs.push_back(context->addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2));
2252 for (
uint p: UUIDs) {
2253 context->setPrimitiveParentObjectID(p, this->OID);
2256 updateTriangleVertices();
2295 for (
int segment = 0; segment < triangle_vertices.size() - 1; segment++) {
2296 vec3 central_axis = (nodes.at(segment + 1) - nodes.at(segment));
2297 float current_length = central_axis.
magnitude();
2298 central_axis = central_axis / current_length;
2299 vec3 dL = central_axis * current_length * (1.f - S);
2301 for (
int downstream_segment = segment + 1; downstream_segment < triangle_vertices.size(); downstream_segment++) {
2302 nodes.at(downstream_segment) = nodes.at(downstream_segment) - dL;
2304 for (
int v = 0; v < triangle_vertices.at(downstream_segment).size(); v++) {
2305 triangle_vertices.at(downstream_segment).at(v) = triangle_vertices.at(downstream_segment).at(v) - dL;
2310 updateTriangleVertices();
2330 if (node_index >= nodes.size()) {
2331 helios_runtime_error(
"ERROR (Tube::pruneTubeNodes): Node index of " + std::to_string(node_index) +
" is out of bounds.");
2334 if (node_index == 0) {
2335 context->deleteObject(this->OID);
2339 nodes.erase(nodes.begin() + node_index, nodes.end());
2340 triangle_vertices.erase(triangle_vertices.begin() + node_index, triangle_vertices.end());
2341 radius.erase(radius.begin() + node_index, radius.end());
2342 colors.erase(colors.begin() + node_index, colors.end());
2345 for (
int i = node_index; i < nodes.size() - 1; i++) {
2346 for (
int j = 0; j < subdiv; j++) {
2347 context->deletePrimitive(UUIDs.at(ii));
2348 context->deletePrimitive(UUIDs.at(ii + 1));
2521 for (
uint UUID: UUIDs) {
2523 const vec3 &v0 = context->getTriangleVertex(UUID, 0);
2524 const vec3 &v1 = context->getTriangleVertex(UUID, 1);
2525 const vec3 &v2 = context->getTriangleVertex(UUID, 2);
2526 volume += (1.f / 6.f) * v0 *
cross(v1, v2);
2528 const vec3 &v0 = context->getTriangleVertex(UUID, 0);
2529 const vec3 &v1 = context->getTriangleVertex(UUID, 1);
2530 const vec3 &v2 = context->getTriangleVertex(UUID, 2);
2531 const vec3 &v3 = context->getTriangleVertex(UUID, 3);
2532 volume += (1.f / 6.f) * v0 *
cross(v1, v2) + (1.f / 6.f) * v0 *
cross(v2, v3);
2535 return std::abs(volume);
2610 std::vector<vec3> nodes_T;
2613 for (
uint i = 0; i < 2; i++) {
2614 nodes_T.at(i).
x = transform[0] * nodes.at(i).x + transform[1] * nodes.at(i).y + transform[2] * nodes.at(i).z + transform[3];
2615 nodes_T.at(i).y = transform[4] * nodes.at(i).x + transform[5] * nodes.at(i).y + transform[6] * nodes.at(i).z + transform[7];
2616 nodes_T.at(i).z = transform[8] * nodes.at(i).x + transform[9] * nodes.at(i).y + transform[10] * nodes.at(i).z + transform[11];
2619 helios::vec3 axis_unit_vector =
helios::make_vec3(nodes_T.at(1).x - nodes_T.at(0).x, nodes_T.at(1).y - nodes_T.at(0).y, nodes_T.at(1).z - nodes_T.at(0).z);
2620 float length = powf(powf(axis_unit_vector.
x, 2) + powf(axis_unit_vector.
y, 2) + powf(axis_unit_vector.
z, 2), 0.5);
2621 axis_unit_vector = axis_unit_vector / length;
2623 return axis_unit_vector;
2642 const std::vector<helios::vec3> &nodes_T = context->getConeObjectPointer(OID)->getNodeCoordinates();
2643 const std::vector<float> &radii_T = context->getConeObjectPointer(OID)->getNodeRadii();
2646 vec3 axis_unit_vector =
helios::make_vec3(nodes_T.at(1).x - nodes_T.at(0).x, nodes_T.at(1).y - nodes_T.at(0).y, nodes_T.at(1).z - nodes_T.at(0).z);
2647 float length = powf(powf(axis_unit_vector.
x, 2) + powf(axis_unit_vector.
y, 2) + powf(axis_unit_vector.
z, 2), 0.5);
2648 axis_unit_vector = axis_unit_vector / length;
2651 context->getConeObjectPointer(OID)->translate(-1.0 * nodes_T.at(0));
2656 vec3 ra =
cross(z_axis, axis_unit_vector);
2658 float dot = axis_unit_vector.
x * z_axis.
x + axis_unit_vector.
y * z_axis.
y + axis_unit_vector.
z * z_axis.
z;
2662 if (angle !=
float(0.0)) {
2663 context->getConeObjectPointer(OID)->rotate(-1 * angle, ra);
2667 float T[16], T_prim[16];
2669 matmult(T, transform, transform);
2670 for (
uint UUID: UUIDs) {
2671 if (context->doesPrimitiveExist(UUID)) {
2672 context->getPrimitiveTransformationMatrix(UUID, T_prim);
2674 context->setPrimitiveTransformationMatrix(UUID, T_prim);
2680 context->getConeObjectPointer(OID)->rotate(angle, ra);
2684 context->getConeObjectPointer(OID)->translate(nodes_T.at(0));
2689 const std::vector<helios::vec3> &nodes_T = context->getConeObjectPointer(OID)->getNodeCoordinates();
2690 const std::vector<float> &radii_T = context->getConeObjectPointer(OID)->getNodeRadii();
2693 vec3 axis_unit_vector =
helios::make_vec3(nodes_T.at(1).x - nodes_T.at(0).x, nodes_T.at(1).y - nodes_T.at(0).y, nodes_T.at(1).z - nodes_T.at(0).z);
2697 context->getConeObjectPointer(OID)->translate(-1.0 * nodes_T.at(0));
2701 vec3 ra =
cross(z_axis, axis_unit_vector);
2703 float dot = axis_unit_vector * z_axis;
2706 if (angle !=
float(0.0)) {
2707 context->getConeObjectPointer(OID)->rotate(-1 * angle, ra);
2711 context->scaleObject(OID,
make_vec3(S, S, 1));
2716 context->getConeObjectPointer(OID)->rotate(angle, ra);
2720 context->getConeObjectPointer(OID)->translate(nodes_T.at(0));