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;
418 patch_new->context_ptr =
this;
421 std::string mat_label = generateMaterialLabel(
make_RGBAcolor(0, 0, 0, 1), texturefile,
false);
423 patch_new->materialID = addMaterial_internal(mat_label,
make_RGBAcolor(0, 0, 0, 1), texturefile);
428 materials[patch_new->materialID].reference_count++;
431 UUID.push_back(currentUUID - 1);
435 auto *tile_new = (
new Tile(currentObjectID, UUID, subdiv, texturefile,
this));
437 float T[16], S[16],
R[16];
440 tile_new->getTransformationMatrix(transform);
443 matmult(S, transform, transform);
451 matmult(T, transform, transform);
452 tile_new->setTransformationMatrix(transform);
455 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
458 tile_new->object_origin = center;
460 objects[currentObjectID] = tile_new;
462 return currentObjectID - 1;
478 const uint node_count = nodes.size();
480 if (node_count == 0) {
482 }
else if (node_count != radius.size()) {
483 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `radius' arguments must agree.");
484 }
else if (node_count != color.size()) {
485 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `color' arguments must agree.");
489 const float min_radius_threshold = 1e-5f;
490 std::vector<float> radius_clamped = radius;
491 for (
int i = 0; i < node_count; i++) {
492 if (radius_clamped[i] < min_radius_threshold && radius_clamped[i] >= 0) {
493 radius_clamped[i] = min_radius_threshold;
498 std::vector<float> cfact(radial_subdivisions + 1);
499 std::vector<float> sfact(radial_subdivisions + 1);
500 std::vector<std::vector<vec3>> triangle_vertices;
501 resize_vector(triangle_vertices, radial_subdivisions + 1, node_count);
504 for (
int j = 0; j < radial_subdivisions + 1; j++) {
505 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
506 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
509 vec3 initial_radial(1.0f, 0.0f, 0.0f);
510 vec3 previous_axial_vector;
511 vec3 previous_radial_dir;
513 for (
int i = 0; i < node_count; i++) {
514 if (radius.at(i) < 0) {
519 axial_vector = nodes[i + 1] - nodes[i];
524 axial_vector = axial_vector / mag;
526 if (fabs(axial_vector * initial_radial) > 0.95f) {
527 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
530 if (fabs(axial_vector.
z) > 0.95f) {
531 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
533 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
535 if (i == node_count - 1) {
536 axial_vector = nodes[i] - nodes[i - 1];
538 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
544 axial_vector = axial_vector / mag;
548 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
550 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
554 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
555 if (fabs(axial_vector * fallback_radial) > 0.95f) {
556 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
558 if (fabs(axial_vector.
z) > 0.95f) {
559 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
561 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
565 previous_axial_vector = axial_vector;
567 vec3 radial_dir = previous_radial_dir;
568 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
571 for (
int j = 0; j < radial_subdivisions + 1; j++) {
572 vec3 normal = cfact[j] * radius_clamped[i] * radial_dir + sfact[j] * radius_clamped[i] * orthogonal_dir;
573 triangle_vertices[i][j] = nodes[i] + normal;
578 std::vector<uint> UUIDs(2 * (node_count - 1) * radial_subdivisions);
582 for (
int j = 0; j < radial_subdivisions; j++) {
583 for (
int i = 0; i < node_count - 1; i++) {
584 v0 = triangle_vertices[i][j];
585 v1 = triangle_vertices[i + 1][j + 1];
586 v2 = triangle_vertices[i][j + 1];
588 UUIDs.at(ii) =
addTriangle(v0, v1, v2, color.at(i));
590 v0 = triangle_vertices[i][j];
591 v1 = triangle_vertices[i + 1][j];
592 v2 = triangle_vertices[i + 1][j + 1];
594 UUIDs.at(ii + 1) =
addTriangle(v0, v1, v2, color.at(i));
600 auto *tube_new = (
new Tube(currentObjectID, UUIDs, nodes, radius, color, triangle_vertices, radial_subdivisions,
"",
this));
602 for (
uint p: UUIDs) {
603 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
606 objects[currentObjectID] = tube_new;
609 uint objID = currentObjectID - 1;
625uint Context::addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile,
const std::vector<float> &textureuv_ufrac) {
626 if (!validateTextureFileExtenstion(texturefile)) {
627 helios_runtime_error(
"ERROR (Context::addTubeObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
628 }
else if (!doesTextureFileExist(texturefile)) {
629 helios_runtime_error(
"ERROR (Context::addTubeObject): Texture file " + std::string(texturefile) +
" does not exist.");
632 const uint node_count = nodes.size();
634 if (node_count == 0) {
636 }
else if (node_count != radius.size()) {
637 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `radius' arguments must agree.");
638 }
else if (node_count != textureuv_ufrac.size()) {
639 helios_runtime_error(
"ERROR (Context::addTubeObject): Size of `nodes' and `textureuv_ufrac' arguments must agree.");
643 const float min_radius_threshold = 1e-5f;
644 std::vector<float> radius_clamped = radius;
645 for (
int i = 0; i < node_count; i++) {
646 if (radius_clamped[i] < min_radius_threshold && radius_clamped[i] >= 0) {
647 radius_clamped[i] = min_radius_threshold;
652 std::vector<float> cfact(radial_subdivisions + 1);
653 std::vector<float> sfact(radial_subdivisions + 1);
654 std::vector<std::vector<vec3>> triangle_vertices;
655 resize_vector(triangle_vertices, radial_subdivisions + 1, node_count);
656 std::vector<std::vector<vec2>> uv;
660 for (
int j = 0; j < radial_subdivisions + 1; j++) {
661 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
662 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
665 vec3 initial_radial(1.0f, 0.0f, 0.0f);
666 vec3 previous_axial_vector;
667 vec3 previous_radial_dir;
669 for (
int i = 0; i < node_count; i++) {
670 if (radius.at(i) < 0) {
675 axial_vector = nodes[i + 1] - nodes[i];
680 axial_vector = axial_vector / mag;
682 if (fabs(axial_vector * initial_radial) > 0.95f) {
683 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
686 if (fabs(axial_vector.
z) > 0.95f) {
687 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
689 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
691 if (i == node_count - 1) {
692 axial_vector = nodes[i] - nodes[i - 1];
694 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
700 axial_vector = axial_vector / mag;
704 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
706 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
710 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
711 if (fabs(axial_vector * fallback_radial) > 0.95f) {
712 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
714 if (fabs(axial_vector.
z) > 0.95f) {
715 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
717 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
721 previous_axial_vector = axial_vector;
723 vec3 radial_dir = previous_radial_dir;
724 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
727 for (
int j = 0; j < radial_subdivisions + 1; j++) {
728 vec3 normal = cfact[j] * radius_clamped[i] * radial_dir + sfact[j] * radius_clamped[i] * orthogonal_dir;
729 triangle_vertices[i][j] = nodes[i] + normal;
731 uv[i][j].
x = textureuv_ufrac[i];
732 uv[i][j].y = float(j) / float(radial_subdivisions);
736 std::vector<uint> UUIDs;
737 UUIDs.reserve(2 * (node_count - 1) * radial_subdivisions);
740 for (
int j = 0; j < radial_subdivisions; j++) {
741 for (
int i = 0; i < node_count - 1; i++) {
742 v0 = triangle_vertices[i][j];
743 v1 = triangle_vertices[i + 1][j + 1];
744 v2 = triangle_vertices[i][j + 1];
747 uv1 = uv[i + 1][j + 1];
750 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
752 UUIDs.push_back(triangle_uuid);
757 v0 = triangle_vertices[i][j];
758 v1 = triangle_vertices[i + 1][j];
759 v2 = triangle_vertices[i + 1][j + 1];
763 uv2 = uv[i + 1][j + 1];
765 uint triangle_uuid2 =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
767 UUIDs.push_back(triangle_uuid2);
774 std::vector<RGBcolor> colors(nodes.size());
776 auto *tube_new = (
new Tube(currentObjectID, UUIDs, nodes, radius, colors, triangle_vertices, radial_subdivisions, texturefile,
this));
778 for (
uint p: UUIDs) {
779 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
782 objects[currentObjectID] = tube_new;
785 uint objID = currentObjectID - 1;
806 if (size.
x <= 0 || size.
y <= 0 || size.
z <= 0) {
808 }
else if (subdiv.
x < 1 || subdiv.
y < 1 || subdiv.
z < 1) {
809 helios_runtime_error(
"ERROR (Context::addBoxObject): Number of box subdivisions must be positive.");
812 std::vector<uint> UUID;
813 UUID.reserve(2 * (subdiv.
z * (subdiv.
x + subdiv.
y) + subdiv.
x * subdiv.
y));
816 subsize.
x = size.
x / float(subdiv.
x);
817 subsize.
y = size.
y / float(subdiv.
y);
818 subsize.
z = size.
z / float(subdiv.
z);
821 std::vector<uint> U, U_copy;
823 if (reverse_normals) {
828 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
830 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());
840 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
842 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());
852 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
854 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());
865 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
867 UUID.insert(UUID.end(), U.begin(), U.end());
870 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
872 UUID.insert(UUID.end(), U.begin(), U.end());
877 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
879 UUID.insert(UUID.end(), U.begin(), U.end());
882 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
884 UUID.insert(UUID.end(), U.begin(), U.end());
889 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
891 UUID.insert(UUID.end(), U.begin(), U.end());
894 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
896 UUID.insert(UUID.end(), U.begin(), U.end());
899 auto *box_new = (
new Box(currentObjectID, UUID, subdiv,
"",
this));
901 float T[16], transform[16];
902 box_new->getTransformationMatrix(transform);
905 matmult(T, transform, transform);
908 matmult(T, transform, transform);
909 box_new->setTransformationMatrix(transform);
911 box_new->setColor(color);
914 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
917 box_new->object_origin = center;
919 objects[currentObjectID] = box_new;
921 return currentObjectID - 1;
925 if (!validateTextureFileExtenstion(texturefile)) {
926 helios_runtime_error(
"ERROR (Context::addBoxObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
927 }
else if (!doesTextureFileExist(texturefile)) {
928 helios_runtime_error(
"ERROR (Context::addBoxObject): Texture file " + std::string(texturefile) +
" does not exist.");
931 std::vector<uint> UUID;
934 subsize.
x = size.
x / float(subdiv.
x);
935 subsize.
y = size.
y / float(subdiv.
y);
936 subsize.
z = size.
z / float(subdiv.
z);
939 std::vector<uint> U, U_copy;
941 if (reverse_normals) {
946 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
948 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());
958 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
960 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());
970 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
972 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());
983 subcenter = center +
make_vec3(0, 0.5f * size.
y, 0);
985 UUID.insert(UUID.end(), U.begin(), U.end());
988 subcenter = center -
make_vec3(0, 0.5f * size.
y, 0);
990 UUID.insert(UUID.end(), U.begin(), U.end());
995 subcenter = center +
make_vec3(0.5f * size.
x, 0, 0);
997 UUID.insert(UUID.end(), U.begin(), U.end());
1000 subcenter = center -
make_vec3(0.5f * size.
x, 0, 0);
1002 UUID.insert(UUID.end(), U.begin(), U.end());
1007 subcenter = center +
make_vec3(0, 0, 0.5f * size.
z);
1009 UUID.insert(UUID.end(), U.begin(), U.end());
1012 subcenter = center -
make_vec3(0, 0, 0.5f * size.
z);
1014 UUID.insert(UUID.end(), U.begin(), U.end());
1017 auto *box_new = (
new Box(currentObjectID, UUID, subdiv, texturefile,
this));
1019 float T[16], transform[16];
1020 box_new->getTransformationMatrix(transform);
1023 matmult(T, transform, transform);
1026 matmult(T, transform, transform);
1027 box_new->setTransformationMatrix(transform);
1029 for (
uint p: UUID) {
1030 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1033 box_new->object_origin = center;
1035 objects[currentObjectID] = box_new;
1037 return currentObjectID - 1;
1065 std::vector<uint> UUID(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
1068 for (
int r = 0; r < Ndivs.
y; r++) {
1069 for (
int t = 0; t < Ndivs.
x; t++) {
1070 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
1071 float theta = dtheta * float(t);
1072 float theta_plus = dtheta * float(t + 1);
1074 float rx = size.
x / float(Ndivs.
y) * float(r);
1075 float ry = size.
y / float(Ndivs.
y) * float(r);
1077 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
1078 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
1083 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);
1085 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);
1087 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
elevation,
"y");
1088 getPrimitivePointer_private(UUID.at(i))->rotate(rotation.
azimuth,
"z");
1089 getPrimitivePointer_private(UUID.at(i))->translate(center);
1095 auto *disk_new = (
new Disk(currentObjectID, UUID, Ndivs,
"",
this));
1097 float T[16], transform[16];
1098 disk_new->getTransformationMatrix(transform);
1101 matmult(T, transform, transform);
1104 matmult(T, transform, transform);
1105 disk_new->setTransformationMatrix(transform);
1107 disk_new->setColor(color);
1109 for (
uint p: UUID) {
1110 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1113 disk_new->object_origin = center;
1115 objects[currentObjectID] = disk_new;
1117 return currentObjectID - 1;
1121 if (!validateTextureFileExtenstion(texturefile)) {
1122 helios_runtime_error(
"ERROR (Context::addDiskObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1123 }
else if (!doesTextureFileExist(texturefile)) {
1124 helios_runtime_error(
"ERROR (Context::addDiskObject): Texture file " + std::string(texturefile) +
" does not exist.");
1127 std::vector<uint> UUID;
1128 UUID.reserve(Ndivs.
x + Ndivs.
x * (Ndivs.
y - 1) * 2);
1129 for (
int r = 0; r < Ndivs.
y; r++) {
1130 for (
int t = 0; t < Ndivs.
x; t++) {
1131 float dtheta = 2.f *
PI_F / float(Ndivs.
x);
1132 float theta = dtheta * float(t);
1133 float theta_plus = dtheta * float(t + 1);
1135 float rx = size.
x / float(Ndivs.
y) * float(r);
1136 float ry = size.
y / float(Ndivs.
y) * float(r);
1137 float rx_plus = size.
x / float(Ndivs.
y) * float(r + 1);
1138 float ry_plus = size.
y / float(Ndivs.
y) * float(r + 1);
1141 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),
1142 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)),
1143 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
1145 UUID.push_back(triangle_uuid);
1151 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,
1152 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)),
1153 make_vec2(0.5f * (1.f + cosf(theta) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta) * ry_plus / size.
y)));
1155 UUID.push_back(triangle_uuid1);
1160 uint triangle_uuid2 =
1161 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,
1162 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)),
1163 make_vec2(0.5f * (1.f + cosf(theta_plus) * rx_plus / size.
x), 0.5f * (1.f + sinf(theta_plus) * ry_plus / size.
y)));
1165 UUID.push_back(triangle_uuid2);
1172 size_t start_idx = UUID.size() - (r == 0 ? 1 : 2);
1173 for (
size_t uuid_idx = start_idx; uuid_idx < UUID.size(); uuid_idx++) {
1174 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
elevation,
"y");
1175 getPrimitivePointer_private(UUID.at(uuid_idx))->rotate(rotation.
azimuth,
"z");
1176 getPrimitivePointer_private(UUID.at(uuid_idx))->translate(center);
1181 auto *disk_new = (
new Disk(currentObjectID, UUID, Ndivs, texturefile,
this));
1183 float T[16], transform[16];
1184 disk_new->getTransformationMatrix(transform);
1187 matmult(T, transform, transform);
1190 matmult(T, transform, transform);
1191 disk_new->setTransformationMatrix(transform);
1193 for (
uint p: UUID) {
1194 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1197 disk_new->object_origin = center;
1199 objects[currentObjectID] = disk_new;
1201 return currentObjectID - 1;
1205 if (UUIDs.empty()) {
1206 helios_runtime_error(
"ERROR (Context::addPolymeshObject): UUIDs array is empty. Cannot create polymesh object.");
1208 helios_runtime_error(
"ERROR (Context::addPolymeshObject): One or more of the provided UUIDs does not exist. Cannot create polymesh object.");
1212 std::vector<uint> UUIDs_polymesh;
1213 UUIDs_polymesh.reserve(UUIDs.size());
1214 size_t skipped_UUIDs = 0;
1215 for (
uint UUID: UUIDs) {
1216 if (getPrimitivePointer_private(UUID)->getParentObjectID() != 0) {
1219 UUIDs_polymesh.push_back(UUID);
1222 if (skipped_UUIDs > 0) {
1223 std::cerr <<
"WARNING (Context::addPolymeshObject): " << skipped_UUIDs <<
" primitives were not added to polymesh object because they already belong to another object." << std::endl;
1226 auto *polymesh_new = (
new Polymesh(currentObjectID, UUIDs_polymesh,
"",
this));
1228 float T[16], transform[16];
1229 polymesh_new->getTransformationMatrix(transform);
1231 makeTranslationMatrix(getPrimitivePointer_private(UUIDs_polymesh.front())->getVertices().front(), T);
1232 matmult(T, transform, transform);
1233 polymesh_new->setTransformationMatrix(transform);
1235 for (
uint UUID: UUIDs_polymesh) {
1236 getPrimitivePointer_private(UUID)->setParentObjectID(currentObjectID);
1239 objects[currentObjectID] = polymesh_new;
1242 uint objID = currentObjectID - 1;
1254 const std::vector nodes{node0, node1};
1255 const std::vector radii{radius0, radius1};
1258 std::vector<float> cfact(Ndivs + 1);
1259 std::vector<float> sfact(Ndivs + 1);
1260 std::vector<std::vector<vec3>> xyz(Ndivs + 1);
1261 std::vector<std::vector<vec3>> normal(Ndivs + 1);
1263 for (
uint j = 0; j < Ndivs + 1; j++) {
1264 xyz.at(j).resize(2);
1265 normal.at(j).resize(2);
1267 vec3 nvec(0.1817f, 0.6198f, 0.7634f);
1269 for (
int j = 0; j < Ndivs + 1; j++) {
1270 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
1271 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
1274 for (
int i = 0; i < 2; i++) {
1279 vec.
x = nodes[i + 1].x - nodes[i].x;
1280 vec.
y = nodes[i + 1].y - nodes[i].y;
1281 vec.
z = nodes[i + 1].z - nodes[i].z;
1282 }
else if (i == 1) {
1283 vec.
x = nodes[i].x - nodes[i - 1].x;
1284 vec.
y = nodes[i].y - nodes[i - 1].y;
1285 vec.
z = nodes[i].z - nodes[i - 1].z;
1292 convec =
cross(nvec, vec);
1296 norm = std::max(convec.
magnitude(), 1e-6f);
1298 convec = convec / norm;
1299 nvec =
cross(vec, convec);
1302 nvec =
cross(convec, vec);
1303 norm = std::max(nvec.
magnitude(), 1e-6f);
1307 for (
int j = 0; j < Ndivs + 1; j++) {
1308 normal[j][i].
x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
1309 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
1310 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
1312 xyz[j][i].x = nodes[i].x + normal[j][i].x;
1313 xyz[j][i].y = nodes[i].y + normal[j][i].y;
1314 xyz[j][i].z = nodes[i].z + normal[j][i].z;
1316 normal[j][i] = normal[j][i] / radii[i];
1321 std::vector<uint> UUID(2 * Ndivs);
1324 for (
int j = 0; j < Ndivs; j++) {
1340 auto *cone_new = (
new Cone(currentObjectID, UUID, node0, node1, radius0, radius1, Ndivs,
"",
this));
1342 for (
uint p: UUID) {
1343 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1346 cone_new->setColor(color);
1348 objects[currentObjectID] = cone_new;
1351 uint objID = currentObjectID - 1;
1358 if (!validateTextureFileExtenstion(texturefile)) {
1359 helios_runtime_error(
"ERROR (Context::addConeObject): Texture file " + std::string(texturefile) +
" is not PNG or JPEG format.");
1360 }
else if (!doesTextureFileExist(texturefile)) {
1361 helios_runtime_error(
"ERROR (Context::addConeObject): Texture file " + std::string(texturefile) +
" does not exist.");
1364 const std::vector<helios::vec3> nodes{node0, node1};
1365 const std::vector<float> radii{radius0, radius1};
1368 std::vector<float> cfact(Ndivs + 1);
1369 std::vector<float> sfact(Ndivs + 1);
1370 std::vector<std::vector<vec3>> xyz, normal;
1371 std::vector<std::vector<vec2>> uv;
1372 xyz.resize(Ndivs + 1);
1373 normal.resize(Ndivs + 1);
1374 uv.resize(Ndivs + 1);
1375 for (
uint j = 0; j < Ndivs + 1; j++) {
1376 xyz.at(j).resize(2);
1377 normal.at(j).resize(2);
1380 vec3 nvec(0.f, 1.f, 0.f);
1382 for (
int j = 0; j < Ndivs + 1; j++) {
1383 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(Ndivs));
1384 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(Ndivs));
1387 for (
int i = 0; i < 2; i++) {
1392 vec.
x = nodes[i + 1].x - nodes[i].x;
1393 vec.
y = nodes[i + 1].y - nodes[i].y;
1394 vec.
z = nodes[i + 1].z - nodes[i].z;
1395 }
else if (i == 1) {
1396 vec.
x = nodes[i].x - nodes[i - 1].x;
1397 vec.
y = nodes[i].y - nodes[i - 1].y;
1398 vec.
z = nodes[i].z - nodes[i - 1].z;
1405 convec =
cross(nvec, vec);
1409 norm = std::max(convec.
magnitude(), 1e-6f);
1411 convec = convec / norm;
1412 nvec =
cross(vec, convec);
1415 nvec =
cross(convec, vec);
1416 norm = std::max(nvec.
magnitude(), 1e-6f);
1420 for (
int j = 0; j < Ndivs + 1; j++) {
1421 normal[j][i].
x = cfact[j] * radii[i] * nvec.
x + sfact[j] * radii[i] * convec.
x;
1422 normal[j][i].y = cfact[j] * radii[i] * nvec.
y + sfact[j] * radii[i] * convec.
y;
1423 normal[j][i].z = cfact[j] * radii[i] * nvec.
z + sfact[j] * radii[i] * convec.
z;
1425 xyz[j][i].x = nodes[i].x + normal[j][i].x;
1426 xyz[j][i].y = nodes[i].y + normal[j][i].y;
1427 xyz[j][i].z = nodes[i].z + normal[j][i].z;
1429 uv[j][i].x = float(i) / float(2 - 1);
1430 uv[j][i].y = float(j) / float(Ndivs);
1432 normal[j][i] = normal[j][i] / radii[i];
1438 std::vector<uint> UUID;
1440 for (
int i = 0; i < 2 - 1; i++) {
1441 for (
int j = 0; j < Ndivs; j++) {
1443 v1 = xyz[j + 1][i + 1];
1447 uv1 = uv[j + 1][i + 1];
1450 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
1451 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1453 UUID.push_back(triangle_uuid);
1461 v2 = xyz[j + 1][i + 1];
1465 uv2 = uv[j + 1][i + 1];
1467 if ((v1 - v0).magnitude() > 1e-6 && (v2 - v0).magnitude() > 1e-6 && (v2 - v1).magnitude() > 1e-6) {
1468 uint triangle_uuid =
addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2);
1470 UUID.push_back(triangle_uuid);
1478 auto *cone_new = (
new Cone(currentObjectID, UUID, node0, node1, radius0, radius1, Ndivs, texturefile,
this));
1480 for (
uint p: UUID) {
1481 getPrimitivePointer_private(p)->setParentObjectID(currentObjectID);
1484 objects[currentObjectID] = cone_new;
1487 uint objID = currentObjectID - 1;
1890Tube::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,
1987 if (node_radius < 0) {
1990 node_radius = std::max((
float) 1e-5, node_radius);
1992 uint radial_subdivisions = subdiv;
1995 std::vector<float> cfact(radial_subdivisions + 1);
1996 std::vector<float> sfact(radial_subdivisions + 1);
1998 for (
int j = 0; j < radial_subdivisions + 1; j++) {
1999 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2000 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2003 triangle_vertices.resize(triangle_vertices.size() + 1);
2004 triangle_vertices.back().resize(radial_subdivisions + 1);
2006 nodes.push_back(node_position);
2007 radius.push_back(node_radius);
2008 colors.push_back(node_color);
2010 int node_count = nodes.size();
2012 vec3 initial_radial(1.0f, 0.0f, 0.0f);
2013 vec3 previous_axial_vector;
2014 vec3 previous_radial_dir;
2016 for (
int i = 0; i < node_count; i++) {
2017 if (radius.at(i) < 0) {
2022 axial_vector = nodes[i + 1] - nodes[i];
2027 axial_vector = axial_vector / mag;
2029 if (fabs(axial_vector * initial_radial) > 0.95f) {
2030 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
2033 if (fabs(axial_vector.
z) > 0.95f) {
2034 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
2036 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
2038 if (i == node_count - 1) {
2039 axial_vector = nodes[i] - nodes[i - 1];
2041 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
2047 axial_vector = axial_vector / mag;
2051 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
2053 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
2057 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2058 if (fabs(axial_vector * fallback_radial) > 0.95f) {
2059 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
2061 if (fabs(axial_vector.
z) > 0.95f) {
2062 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2064 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
2078 previous_axial_vector = axial_vector;
2080 vec3 radial_dir = previous_radial_dir;
2081 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
2084 if (i < node_count - 2) {
2088 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2089 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
2090 triangle_vertices[i][j] = nodes[i] + normal;
2096 int second_last = node_count - 2;
2097 int last = node_count - 1;
2098 for (
int j = 0; j < radial_subdivisions; j++) {
2099 vec3 v0 = triangle_vertices.at(second_last).at(j);
2100 vec3 v1 = triangle_vertices.at(last).at(j + 1);
2101 vec3 v2 = triangle_vertices.at(second_last).at(j + 1);
2103 UUIDs.push_back(context->addTriangle(v0, v1, v2, node_color));
2105 v0 = triangle_vertices.at(second_last).at(j);
2106 v1 = triangle_vertices.at(last).at(j);
2107 v2 = triangle_vertices.at(last).at(j + 1);
2109 UUIDs.push_back(context->addTriangle(v0, v1, v2, node_color));
2112 for (
uint p: UUIDs) {
2113 context->setPrimitiveParentObjectID(p, this->OID);
2116 updateTriangleVertices();
2122 if (node_radius < 0) {
2124 }
else if (textureuv_ufrac.
x < 0 || textureuv_ufrac.
y < 0 || textureuv_ufrac.
x > 1 || textureuv_ufrac.
y > 1) {
2125 helios_runtime_error(
"ERROR (Tube::appendTubeSegment): Texture U fraction must be between 0 and 1.");
2127 node_radius = std::max((
float) 1e-5, node_radius);
2129 uint radial_subdivisions = subdiv;
2132 std::vector<float> cfact(radial_subdivisions + 1);
2133 std::vector<float> sfact(radial_subdivisions + 1);
2135 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2136 cfact[j] = cosf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2137 sfact[j] = sinf(2.f *
PI_F *
float(j) /
float(radial_subdivisions));
2140 triangle_vertices.resize(triangle_vertices.size() + 1);
2141 triangle_vertices.back().resize(radial_subdivisions + 1);
2142 std::vector<std::vector<vec2>> uv;
2145 nodes.push_back(node_position);
2146 radius.push_back(node_radius);
2147 colors.push_back(RGB::black);
2149 int node_count = nodes.size();
2151 vec3 initial_radial(1.0f, 0.0f, 0.0f);
2152 vec3 previous_axial_vector;
2153 vec3 previous_radial_dir;
2155 for (
int i = 0; i < node_count; i++) {
2156 if (radius.at(i) < 0) {
2161 axial_vector = nodes[i + 1] - nodes[i];
2166 axial_vector = axial_vector / mag;
2168 if (fabs(axial_vector * initial_radial) > 0.95f) {
2169 initial_radial =
vec3(0.0f, 1.0f, 0.0f);
2172 if (fabs(axial_vector.
z) > 0.95f) {
2173 initial_radial =
vec3(1.0f, 0.0f, 0.0f);
2175 previous_radial_dir =
cross(axial_vector, initial_radial).
normalize();
2177 if (i == node_count - 1) {
2178 axial_vector = nodes[i] - nodes[i - 1];
2180 axial_vector = 0.5f * ((nodes[i] - nodes[i - 1]) + (nodes[i + 1] - nodes[i]));
2186 axial_vector = axial_vector / mag;
2190 vec3 rotation_axis =
cross(previous_axial_vector, axial_vector);
2192 float angle = acos(std::clamp(previous_axial_vector * axial_vector, -1.0f, 1.0f));
2196 vec3 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2197 if (fabs(axial_vector * fallback_radial) > 0.95f) {
2198 fallback_radial =
vec3(0.0f, 1.0f, 0.0f);
2200 if (fabs(axial_vector.
z) > 0.95f) {
2201 fallback_radial =
vec3(1.0f, 0.0f, 0.0f);
2203 previous_radial_dir =
cross(axial_vector, fallback_radial).
normalize();
2207 previous_axial_vector = axial_vector;
2209 vec3 radial_dir = previous_radial_dir;
2210 vec3 orthogonal_dir =
cross(radial_dir, axial_vector);
2213 if (i < node_count - 2) {
2217 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2218 vec3 normal = cfact[j] * radius[i] * radial_dir + sfact[j] * radius[i] * orthogonal_dir;
2219 triangle_vertices[i][j] = nodes[i] + normal;
2223 std::vector<float> ufrac{textureuv_ufrac.
x, textureuv_ufrac.
y};
2224 for (
int i = 0; i < 2; i++) {
2225 for (
int j = 0; j < radial_subdivisions + 1; j++) {
2226 uv[i][j].x = ufrac[i];
2227 uv[i][j].y = float(j) / float(radial_subdivisions);
2231 int old_triangle_count = UUIDs.size();
2237 for (
int j = 0; j < radial_subdivisions; j++) {
2238 v0 = triangle_vertices[node_count - 2][j];
2239 v1 = triangle_vertices[node_count - 1][j + 1];
2240 v2 = triangle_vertices[node_count - 2][j + 1];
2246 UUIDs.push_back(context->addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2));
2248 v0 = triangle_vertices[node_count - 2][j];
2249 v1 = triangle_vertices[node_count - 1][j];
2250 v2 = triangle_vertices[node_count - 1][j + 1];
2256 UUIDs.push_back(context->addTriangle(v0, v1, v2, texturefile, uv0, uv1, uv2));
2259 for (
uint p: UUIDs) {
2260 context->setPrimitiveParentObjectID(p, this->OID);
2263 updateTriangleVertices();
2337 if (node_index >= nodes.size()) {
2338 helios_runtime_error(
"ERROR (Tube::pruneTubeNodes): Node index of " + std::to_string(node_index) +
" is out of bounds.");
2341 if (node_index == 0) {
2342 context->deleteObject(this->OID);
2346 nodes.erase(nodes.begin() + node_index, nodes.end());
2347 triangle_vertices.erase(triangle_vertices.begin() + node_index, triangle_vertices.end());
2348 radius.erase(radius.begin() + node_index, radius.end());
2349 colors.erase(colors.begin() + node_index, colors.end());
2352 for (
int i = node_index; i < nodes.size() - 1; i++) {
2353 for (
int j = 0; j < subdiv; j++) {
2354 context->deletePrimitive(UUIDs.at(ii));
2355 context->deletePrimitive(UUIDs.at(ii + 1));
2501 for (
uint UUID: UUIDs) {
2503 const vec3 &v0 = context->getTriangleVertex(UUID, 0);
2504 const vec3 &v1 = context->getTriangleVertex(UUID, 1);
2505 const vec3 &v2 = context->getTriangleVertex(UUID, 2);
2506 volume += (1.f / 6.f) * v0 *
cross(v1, v2);
2508 const vec3 &v0 = context->getTriangleVertex(UUID, 0);
2509 const vec3 &v1 = context->getTriangleVertex(UUID, 1);
2510 const vec3 &v2 = context->getTriangleVertex(UUID, 2);
2511 const vec3 &v3 = context->getTriangleVertex(UUID, 3);
2512 volume += (1.f / 6.f) * v0 *
cross(v1, v2) + (1.f / 6.f) * v0 *
cross(v2, v3);
2515 return std::abs(volume);
2581 std::vector<vec3> nodes_T;
2584 for (
uint i = 0; i < 2; i++) {
2585 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];
2586 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];
2587 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];
2590 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);
2591 float length = powf(powf(axis_unit_vector.
x, 2) + powf(axis_unit_vector.
y, 2) + powf(axis_unit_vector.
z, 2), 0.5);
2592 axis_unit_vector = axis_unit_vector / length;
2594 return axis_unit_vector;
2617 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);
2618 float length = powf(powf(axis_unit_vector.
x, 2) + powf(axis_unit_vector.
y, 2) + powf(axis_unit_vector.
z, 2), 0.5);
2619 axis_unit_vector = axis_unit_vector / length;
2627 vec3 ra =
cross(z_axis, axis_unit_vector);
2629 float dot = axis_unit_vector.
x * z_axis.
x + axis_unit_vector.
y * z_axis.
y + axis_unit_vector.
z * z_axis.
z;
2638 float T[16], T_prim[16];
2640 matmult(T, transform, transform);
2641 for (
uint UUID: UUIDs) {
2642 if (context->doesPrimitiveExist(UUID)) {
2643 context->getPrimitiveTransformationMatrix(UUID, T_prim);
2645 context->setPrimitiveTransformationMatrix(UUID, T_prim);