18using namespace helios;
21 return addPatch(
make_vec3(0, 0, 0),
make_vec2(1, 1),
make_SphericalCoord(0, 0),
make_RGBAcolor(0, 0, 0, 1));
37 if (size.
x < 1e-6f || size.
y < 1e-6f) {
38 helios_runtime_error(
"ERROR (Context::addPatch): Size of patch must be greater than 1e-6 to avoid numerical precision issues.");
41 auto *patch_new = (
new Patch(color, 0, currentUUID));
50 patch_new->rotate(-rotation.
elevation,
"x");
53 patch_new->rotate(-rotation.
azimuth,
"z");
56 patch_new->translate(center);
58 primitives[currentUUID] = patch_new;
60 invalidateAllUUIDsCache();
61 return currentUUID - 1;
65 addTexture(texture_file);
68 const std::vector<helios::vec2> uv = {{0.f, 0.f}, {1.f, 0.f}, {1.f, 1.f}, {0.f, 1.f}};
70 auto *patch_new = (
new Patch(texture_file, uv, textures, 0, currentUUID));
76 assert(size.
x > 0.f && size.
y > 0.f);
80 patch_new->rotate(-rotation.
elevation,
"x");
83 patch_new->rotate(-rotation.
azimuth,
"z");
86 patch_new->translate(center);
88 primitives[currentUUID] = patch_new;
90 invalidateAllUUIDsCache();
91 return currentUUID - 1;
95 if (size.
x < 1e-6f || size.
y < 1e-6f) {
96 helios_runtime_error(
"ERROR (Context::addPatch): Size of patch must be greater than 1e-6 to avoid numerical precision issues.");
99 if (uv_center.
x - 0.5 * uv_size.
x < -1e-3 || uv_center.
y - 0.5 * uv_size.
y < -1e-3 || uv_center.
x + 0.5 * uv_size.
x - 1.f > 1e-3 || uv_center.
y + 0.5 * uv_size.
y - 1.f > 1e-3) {
100 helios_runtime_error(
"ERROR (Context::addPatch): Invalid texture coordinates. uv_center-0.5*uv_size should be >=0 and uv_center+0.5*uv_size should be <=1.");
103 addTexture(texture_file);
105 const std::vector<helios::vec2> uv = {uv_center +
make_vec2(-0.5f * uv_size.
x, -0.5f * uv_size.
y), uv_center +
make_vec2(+0.5f * uv_size.
x, -0.5f * uv_size.
y), uv_center +
make_vec2(+0.5f * uv_size.
x, +0.5f * uv_size.
y),
106 uv_center +
make_vec2(-0.5f * uv_size.
x, +0.5f * uv_size.
y)};
108 auto *patch_new = (
new Patch(texture_file, uv, textures, 0, currentUUID));
114 assert(size.
x > 0.f && size.
y > 0.f);
118 patch_new->rotate(-rotation.
elevation,
"x");
121 patch_new->rotate(-rotation.
azimuth,
"z");
124 patch_new->translate(center);
126 primitives[currentUUID] = patch_new;
128 invalidateAllUUIDsCache();
129 return currentUUID - 1;
141 auto *tri_new = (
new Triangle(vertex0, vertex1, vertex2, color, 0, currentUUID));
145 std::cerr <<
"WARNING (Context::addTriangle): Triangle is malformed and has near-zero surface area." << std::endl;
149 primitives[currentUUID] = tri_new;
151 invalidateAllUUIDsCache();
152 return currentUUID - 1;
156 addTexture(texture_file);
158 const std::vector<helios::vec2> uv{uv0, uv1, uv2};
160 auto *tri_new = (
new Triangle(vertex0, vertex1, vertex2, texture_file, uv, textures, 0, currentUUID));
164 std::cerr <<
"WARNING (Context::addTriangle): Triangle is malformed and has near-zero surface area." << std::endl;
168 primitives[currentUUID] = tri_new;
170 invalidateAllUUIDsCache();
171 return currentUUID - 1;
187 auto *voxel_new = (
new Voxel(color, 0, currentUUID));
189 if (size.
x * size.
y * size.
z == 0) {
193 voxel_new->scale(size);
196 voxel_new->rotate(rotation,
"z");
199 voxel_new->translate(center);
201 primitives[currentUUID] = voxel_new;
203 invalidateAllUUIDsCache();
204 return currentUUID - 1;
208 getPrimitivePointer_private(UUID)->translate(shift);
215 for (
uint UUID: UUIDs) {
216 getPrimitivePointer_private(UUID)->applyTransform(T);
221 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
225 if (rotation_rad == 0) {
230 if (strcmp(axis,
"z") == 0) {
232 }
else if (strcmp(axis,
"y") == 0) {
234 }
else if (strcmp(axis,
"x") == 0) {
237 helios_runtime_error(
"ERROR (Context::rotatePrimitive): Rotation axis should be one of x, y, or z.");
240 for (
uint UUID: UUIDs) {
241 if (strcmp(axis,
"z") != 0 && getPrimitivePointer_private(UUID)->getType() ==
PRIMITIVE_TYPE_VOXEL) {
242 std::cerr <<
"WARNING (Context::rotatePrimitive): Voxels can only be rotate about the z-axis. Ignoring this rotation." << std::endl;
244 getPrimitivePointer_private(UUID)->applyTransform(T);
249 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
253 if (rotation_rad == 0) {
260 for (
uint UUID: UUIDs) {
262 std::cerr <<
"WARNING (Context::rotatePrimitive): Voxels can only be rotate about the z-axis. Ignoring this rotation." << std::endl;
264 getPrimitivePointer_private(UUID)->applyTransform(T);
269 getPrimitivePointer_private(UUID)->rotate(rotation_rad, origin, axis);
273 if (rotation_rad == 0) {
280 for (
uint UUID: UUIDs) {
282 std::cerr <<
"WARNING (Context::rotatePrimitive): Voxels can only be rotate about the z-axis. Ignoring this rotation." << std::endl;
284 getPrimitivePointer_private(UUID)->applyTransform(T);
291 helios_runtime_error(
"ERROR (Context::setPrimitiveNormal): UUID of " + std::to_string(UUID) +
" not found in the context.");
295 auto *prim = getPrimitivePointer_private(UUID);
302 float d = std::clamp(oldN * newN, -1.f, 1.f);
303 float angle = acosf(d);
306 axis = (std::fabs(oldN.
x) < std::fabs(oldN.
z)) ?
cross(oldN, {1, 0, 0}) :
cross(oldN, {0, 0, 1});
316 prim->getTransformationMatrix(M_old);
328 helios::vec3 t1{M_delta[0] * t0.
x + M_delta[1] * t0.y + M_delta[2] * t0.z, M_delta[4] * t0.x + M_delta[5] * t0.y + M_delta[6] * t0.z, M_delta[8] * t0.x + M_delta[9] * t0.y + M_delta[10] * t0.z};
334 targ = normalize(targ);
338 float twist = std::atan2(newN *
cross(t1, targ),
347 float temp[16], M_new[16];
352 prim->setTransformationMatrix(M_new);
356 for (
uint UUID: UUIDs) {
368 auto *prim = getPrimitivePointer_private(UUID);
369 vec3 oldN = prim->getNormal();
390 auto *prim = getPrimitivePointer_private(UUID);
391 vec3 oldN = prim->getNormal();
408 helios_runtime_error(
"ERROR (Context::scalePrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
411 if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
418 getPrimitivePointer_private(UUID)->applyTransform(T);
422 for (
uint UUID: UUIDs) {
430 helios_runtime_error(
"ERROR (Context::scalePrimitiveAboutPoint): UUID of " + std::to_string(UUID) +
" not found in the context.");
433 if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
437 getPrimitivePointer_private(UUID)->scale(S, point);
441 for (
uint UUID: UUIDs) {
447 for (
uint UUID: UUIDs) {
453 if (primitives.find(UUID) == primitives.end()) {
454 helios_runtime_error(
"ERROR (Context::deletePrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
457 Primitive *prim = primitives.at(UUID);
459 for (
const auto &[label, type]: prim->primitive_data_types) {
460 decrementPrimitiveDataLabelCounter(label);
463 if (prim->getParentObjectID() != 0) {
465 uint ObjID = prim->getParentObjectID();
467 objects.at(ObjID)->deleteChildPrimitive(UUID);
468 if (getObjectPointer_private(ObjID)->getPrimitiveUUIDs().empty()) {
471 objects.erase(ObjID);
477 primitives.erase(UUID);
478 dirty_deleted_primitives.push_back(UUID);
479 invalidateAllUUIDsCache();
483 std::vector<uint> UUIDs_copy(UUIDs.size());
485 for (
uint UUID: UUIDs) {
494 if (primitives.find(UUID) == primitives.end()) {
495 helios_runtime_error(
"ERROR (Context::copyPrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
499 uint parentID = primitives.at(UUID)->getParentObjectID();
500 bool textureoverride = primitives.at(UUID)->isTextureColorOverridden();
503 Patch *p = getPatchPointer_private(UUID);
504 const std::vector<vec2> &uv = p->getTextureUV();
505 const vec2 &size = p->getSize();
506 float solid_fraction = p->getArea() / (size.
x * size.
y);
508 if (!p->hasTexture()) {
509 patch_new = (
new Patch(p->getColorRGBA(), parentID, currentUUID));
511 const std::string &texture_file = p->getTextureFile();
512 if (uv.size() == 4) {
513 patch_new = (
new Patch(texture_file.c_str(), solid_fraction, parentID, currentUUID));
514 patch_new->setTextureUV(uv);
516 patch_new = (
new Patch(texture_file.c_str(), solid_fraction, parentID, currentUUID));
520 p->getTransformationMatrix(transform);
521 patch_new->setTransformationMatrix(transform);
522 primitives[currentUUID] = patch_new;
524 Triangle *p = getTrianglePointer_private(UUID);
525 const std::vector<vec3> &vertices = p->getVertices();
526 const std::vector<vec2> &uv = p->getTextureUV();
528 if (!p->hasTexture()) {
529 tri_new = (
new Triangle(vertices.at(0), vertices.at(1), vertices.at(2), p->getColorRGBA(), parentID, currentUUID));
531 const std::string &texture_file = p->getTextureFile();
532 float solid_fraction = p->getArea() /
calculateTriangleArea(vertices.at(0), vertices.at(1), vertices.at(2));
533 tri_new = (
new Triangle(vertices.at(0), vertices.at(1), vertices.at(2), texture_file.c_str(), uv, solid_fraction, parentID, currentUUID));
534 tri_new->setSolidFraction(solid_fraction);
537 p->getTransformationMatrix(transform);
538 tri_new->setTransformationMatrix(transform);
539 primitives[currentUUID] = tri_new;
541 Voxel *p = getVoxelPointer_private(UUID);
544 voxel_new = (
new Voxel(p->getColorRGBA(), parentID, currentUUID));
550 p->getTransformationMatrix(transform);
551 voxel_new->setTransformationMatrix(transform);
552 primitives[currentUUID] = voxel_new;
557 if (textureoverride) {
558 getPrimitivePointer_private(currentUUID)->overrideTextureColor();
562 invalidateAllUUIDsCache();
563 return currentUUID - 1;
566Primitive *Context::getPrimitivePointer_private(
uint UUID)
const {
568 if (primitives.find(UUID) == primitives.end()) {
569 helios_runtime_error(
"ERROR (Context::getPrimitivePointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
572 return primitives.at(UUID);
576 return primitives.find(UUID) != primitives.end();
583 for (
uint UUID: UUIDs) {
591Patch *Context::getPatchPointer_private(
uint UUID)
const {
593 if (primitives.find(UUID) == primitives.end()) {
594 helios_runtime_error(
"ERROR (Context::getPatchPointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
595 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_PATCH) {
596 helios_runtime_error(
"ERROR (Context::getPatchPointer_private): UUID of " + std::to_string(UUID) +
" is not a patch.");
599 return dynamic_cast<Patch *
>(primitives.at(UUID));
604 if (primitives.find(UUID) == primitives.end()) {
605 helios_runtime_error(
"ERROR (Context::getPatchSize): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
607 helios_runtime_error(
"ERROR (Context::getPatchSize): UUID of " + std::to_string(UUID) +
" is not a patch.");
610 return dynamic_cast<Patch *
>(primitives.at(UUID))->getSize();
615 if (primitives.find(UUID) == primitives.end()) {
616 helios_runtime_error(
"ERROR (Context::getPatchCenter): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
618 helios_runtime_error(
"ERROR (Context::getPatchCenter): UUID of " + std::to_string(UUID) +
" is not a patch.");
621 return dynamic_cast<Patch *
>(primitives.at(UUID))->getCenter();
624Triangle *Context::getTrianglePointer_private(
uint UUID)
const {
626 if (primitives.find(UUID) == primitives.end()) {
627 helios_runtime_error(
"ERROR (Context::getTrianglePointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
628 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_TRIANGLE) {
629 helios_runtime_error(
"ERROR (Context::getTrianglePointer_private): UUID of " + std::to_string(UUID) +
" is not a triangle.");
632 return dynamic_cast<Triangle *
>(primitives.at(UUID));
637 if (primitives.find(UUID) == primitives.end()) {
638 helios_runtime_error(
"ERROR (Context::getTriangleVertex): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
640 helios_runtime_error(
"ERROR (Context::getTriangleVertex): UUID of " + std::to_string(UUID) +
" is not a triangle.");
641 }
else if (number > 2) {
642 helios_runtime_error(
"ERROR (Context::getTriangleVertex): Vertex index must be one of 0, 1, or 2.");
645 return dynamic_cast<Triangle *
>(primitives.at(UUID))->getVertex(number);
650 if (primitives.find(UUID) == primitives.end()) {
651 helios_runtime_error(
"ERROR (Context::setTriangleVertices): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
654 dynamic_cast<Triangle *
>(primitives.at(UUID))->setVertices(vertex0, vertex1, vertex2);
657Voxel *Context::getVoxelPointer_private(
uint UUID)
const {
659 if (primitives.find(UUID) == primitives.end()) {
660 helios_runtime_error(
"ERROR (Context::getVoxelPointer): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
661 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_VOXEL) {
662 helios_runtime_error(
"ERROR (Context::getVoxelPointer): UUID of " + std::to_string(UUID) +
" is not a voxel.");
665 return dynamic_cast<Voxel *
>(primitives.at(UUID));
670 if (primitives.find(UUID) == primitives.end()) {
671 helios_runtime_error(
"ERROR (Context::getVoxelSize): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
673 helios_runtime_error(
"ERROR (Context::getVoxelSize): UUID of " + std::to_string(UUID) +
" is not a patch.");
676 return dynamic_cast<Voxel *
>(primitives.at(UUID))->getSize();
681 if (primitives.find(UUID) == primitives.end()) {
682 helios_runtime_error(
"ERROR (Context::getVoxelCenter): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
684 helios_runtime_error(
"ERROR (Context::getVoxelCenter): UUID of " + std::to_string(UUID) +
" is not a patch.");
687 return dynamic_cast<Voxel *
>(primitives.at(UUID))->getCenter();
691 if (include_hidden_primitives) {
692 return primitives.size();
695 for (
const auto &[UUID, primitive]: primitives) {
696 if (!primitive->ishidden) {
706 for (
const auto &[UUID, primitive]: primitives) {
716 for (
const auto &[UUID, primitive]: primitives) {
717 if (primitive->getType() ==
PRIMITIVE_TYPE_PATCH && (include_hidden_primitives || !primitive->ishidden)) {
727Primitive::~Primitive() =
default;
729uint Primitive::getUUID()
const {
737void Primitive::setParentObjectID(
uint objID) {
738 parent_object_ID = objID;
741uint Primitive::getParentObjectID()
const {
742 return parent_object_ID;
745void Primitive::getTransformationMatrix(
float (&T)[16])
const {
746 std::memcpy(T, transform, 16 *
sizeof(
float));
749void Primitive::setTransformationMatrix(
float (&T)[16]) {
750 std::memcpy(transform, T, 16 *
sizeof(
float));
754float Patch::getArea()
const {
755 const vec2 &size = getSize();
757 return size.
x * size.
y * solid_fraction;
760float Triangle::getArea()
const {
761 const std::vector<vec3> &vertices = getVertices();
765 return area * solid_fraction;
768float Voxel::getArea()
const {
769 const vec3 size(transform[0], transform[5], transform[10]);
771 return 2.f * size.x * size.y + 2.f * size.x * size.z + 2.f * size.y * size.z;
774vec3 Patch::getNormal()
const {
775 return normalize(
make_vec3(transform[2], transform[6], transform[10]));
778vec3 Triangle::getNormal()
const {
779 const std::vector<vec3> &vertices = getVertices();
780 return normalize(
cross(vertices[1] - vertices[0], vertices[2] - vertices[1]));
783vec3 Voxel::getNormal()
const {
787std::vector<vec3> Patch::getVertices()
const {
788 std::vector<vec3> vertices(4);
790 const std::vector<vec3> Y = {{-0.5f, -0.5f, 0.f}, {0.5f, -0.5f, 0.f}, {0.5f, 0.5f, 0.f}, {-0.5f, 0.5f, 0.f}};
792 for (
int i = 0; i < 4; i++) {
793 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
794 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
795 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
800std::vector<vec3> Triangle::getVertices()
const {
801 std::vector<vec3> vertices(3);
803 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
805 for (
int i = 0; i < 3; i++) {
806 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
807 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
808 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
813std::vector<vec3> Voxel::getVertices()
const {
814 std::vector<vec3> vertices(8);
816 const std::vector<vec3> Y = {{-0.5f, -0.5f, -0.5f}, {0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, -0.5f}, {-0.5f, 0.5f, -0.5f}, {-0.5f, -0.5f, 0.5f}, {0.5f, -0.5f, 0.5f}, {0.5f, 0.5f, 0.5f}, {-0.5f, 0.5f, 0.5f}};
819 for (
int i = 0; i < 8; i++) {
820 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
821 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
822 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
827RGBcolor Primitive::getColor()
const {
828 return {color.
r, color.g, color.b};
831RGBcolor Primitive::getColorRGB()
const {
832 return {color.
r, color.g, color.b};
835RGBAcolor Primitive::getColorRGBA()
const {
859bool Primitive::hasTexture()
const {
860 if (texturefile.empty()) {
867std::string Primitive::getTextureFile()
const {
871void Primitive::setTextureFile(
const char *texture) {
872 texturefile = texture;
876std::vector<vec2> Primitive::getTextureUV() {
880void Primitive::setTextureUV(
const std::vector<vec2> &a_uv) {
885void Primitive::overrideTextureColor() {
891 texturecoloroverridden =
true;
895void Primitive::useTextureColor() {
901 texturecoloroverridden =
false;
905bool Primitive::isTextureColorOverridden()
const {
906 return texturecoloroverridden;
909float Primitive::getSolidFraction()
const {
910 return solid_fraction;
913void Primitive::setSolidFraction(
float solidFraction) {
914 solid_fraction = solidFraction;
919 return ((c.
y - a.
y) * (b.
x - a.
x) - (c.
x - a.
x) * (b.
y - a.
y) >= 0);
923 makeTransformationMatrix(vertex0, vertex1, vertex2);
927void Primitive::applyTransform(
float (&T)[16]) {
928 if (parent_object_ID != 0) {
929 std::cerr <<
"WARNING (Primitive::applyTransform): Cannot transform individual primitives within a compound object. Use the setter function for objects." << std::endl;
933 matmult(T, transform, transform);
937void Primitive::scale(
const vec3 &S) {
938 if (parent_object_ID != 0) {
939 std::cerr <<
"WARNING (Primitive::scale): Cannot scale individual primitives within a compound object. Use the setter function for objects." << std::endl;
942 if (S.
x == 0 || S.
y == 0 || S.
z == 0) {
944 }
else if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
950 matmult(T, transform, transform);
954void Primitive::scale(
const vec3 &S,
const vec3 &point) {
955 if (parent_object_ID != 0) {
956 std::cerr <<
"WARNING (Primitive::scale): Cannot scale individual primitives within a compound object. Use the setter function for objects." << std::endl;
959 if (S.
x == 0 || S.
y == 0 || S.
z == 0) {
961 }
else if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
967 matmult(T, transform, transform);
972 if (parent_object_ID != 0) {
973 std::cerr <<
"WARNING (Primitive::translate): Cannot translate individual primitives within a compound object. Use the setter function for objects." << std::endl;
977 if (shift == nullorigin) {
983 matmult(T, transform, transform);
987void Patch::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
988 if (parent_object_ID != 0) {
989 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
992 if (rotation_radians == 0) {
996 if (strcmp(rotation_axis_xyz_string,
"z") == 0) {
999 matmult(Rz, transform, transform);
1000 }
else if (strcmp(rotation_axis_xyz_string,
"y") == 0) {
1003 matmult(Ry, transform, transform);
1004 }
else if (strcmp(rotation_axis_xyz_string,
"x") == 0) {
1007 matmult(Rx, transform, transform);
1014void Patch::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1015 if (parent_object_ID != 0) {
1016 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1019 if (rotation_radians == 0) {
1030 if (parent_object_ID != 0) {
1031 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1034 if (rotation_radians == 0) {
1044void Triangle::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
1045 if (parent_object_ID != 0) {
1046 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1049 if (rotation_radians == 0) {
1053 if (strcmp(rotation_axis_xyz_string,
"z") == 0) {
1056 matmult(Rz, transform, transform);
1057 }
else if (strcmp(rotation_axis_xyz_string,
"y") == 0) {
1060 matmult(Ry, transform, transform);
1061 }
else if (strcmp(rotation_axis_xyz_string,
"x") == 0) {
1064 matmult(Rx, transform, transform);
1071void Triangle::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1072 if (parent_object_ID != 0) {
1073 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1076 if (rotation_radians == 0) {
1086void Triangle::rotate(
float rotation_radians,
const helios::vec3 &origin,
const helios::vec3 &rotation_axis_vector) {
1087 if (parent_object_ID != 0) {
1088 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1091 if (rotation_radians == 0) {
1101void Voxel::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
1102 if (parent_object_ID != 0) {
1103 std::cerr <<
"WARNING (Voxel::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1106 if (rotation_radians == 0) {
1112 matmult(Rz, transform, transform);
1116void Voxel::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1117 std::cerr <<
"WARNING (Voxel::rotate) - Voxels can only be rotated about the z-axis. Ignoring this call to rotate()." << std::endl;
1121 std::cerr <<
"WARNING (Voxel::rotate) - Voxels can only be rotated about the z-axis. Ignoring this call to rotate()." << std::endl;
1215 double inv[16], det, invV1[16];
1217 inv[0] = V1[5] * V1[10] * V1[15] - V1[5] * V1[11] * V1[14] - V1[9] * V1[6] * V1[15] + V1[9] * V1[7] * V1[14] + V1[13] * V1[6] * V1[11] - V1[13] * V1[7] * V1[10];
1219 inv[4] = -V1[4] * V1[10] * V1[15] + V1[4] * V1[11] * V1[14] + V1[8] * V1[6] * V1[15] - V1[8] * V1[7] * V1[14] - V1[12] * V1[6] * V1[11] + V1[12] * V1[7] * V1[10];
1221 inv[8] = V1[4] * V1[9] * V1[15] - V1[4] * V1[11] * V1[13] - V1[8] * V1[5] * V1[15] + V1[8] * V1[7] * V1[13] + V1[12] * V1[5] * V1[11] - V1[12] * V1[7] * V1[9];
1223 inv[12] = -V1[4] * V1[9] * V1[14] + V1[4] * V1[10] * V1[13] + V1[8] * V1[5] * V1[14] - V1[8] * V1[6] * V1[13] - V1[12] * V1[5] * V1[10] + V1[12] * V1[6] * V1[9];
1225 inv[1] = -V1[1] * V1[10] * V1[15] + V1[1] * V1[11] * V1[14] + V1[9] * V1[2] * V1[15] - V1[9] * V1[3] * V1[14] - V1[13] * V1[2] * V1[11] + V1[13] * V1[3] * V1[10];
1227 inv[5] = V1[0] * V1[10] * V1[15] - V1[0] * V1[11] * V1[14] - V1[8] * V1[2] * V1[15] + V1[8] * V1[3] * V1[14] + V1[12] * V1[2] * V1[11] - V1[12] * V1[3] * V1[10];
1229 inv[9] = -V1[0] * V1[9] * V1[15] + V1[0] * V1[11] * V1[13] + V1[8] * V1[1] * V1[15] - V1[8] * V1[3] * V1[13] - V1[12] * V1[1] * V1[11] + V1[12] * V1[3] * V1[9];
1231 inv[13] = V1[0] * V1[9] * V1[14] - V1[0] * V1[10] * V1[13] - V1[8] * V1[1] * V1[14] + V1[8] * V1[2] * V1[13] + V1[12] * V1[1] * V1[10] - V1[12] * V1[2] * V1[9];
1233 inv[2] = V1[1] * V1[6] * V1[15] - V1[1] * V1[7] * V1[14] - V1[5] * V1[2] * V1[15] + V1[5] * V1[3] * V1[14] + V1[13] * V1[2] * V1[7] - V1[13] * V1[3] * V1[6];
1235 inv[6] = -V1[0] * V1[6] * V1[15] + V1[0] * V1[7] * V1[14] + V1[4] * V1[2] * V1[15] - V1[4] * V1[3] * V1[14] - V1[12] * V1[2] * V1[7] + V1[12] * V1[3] * V1[6];
1237 inv[10] = V1[0] * V1[5] * V1[15] - V1[0] * V1[7] * V1[13] - V1[4] * V1[1] * V1[15] + V1[4] * V1[3] * V1[13] + V1[12] * V1[1] * V1[7] - V1[12] * V1[3] * V1[5];
1239 inv[14] = -V1[0] * V1[5] * V1[14] + V1[0] * V1[6] * V1[13] + V1[4] * V1[1] * V1[14] - V1[4] * V1[2] * V1[13] - V1[12] * V1[1] * V1[6] + V1[12] * V1[2] * V1[5];
1241 inv[3] = -V1[1] * V1[6] * V1[11] + V1[1] * V1[7] * V1[10] + V1[5] * V1[2] * V1[11] - V1[5] * V1[3] * V1[10] - V1[9] * V1[2] * V1[7] + V1[9] * V1[3] * V1[6];
1243 inv[7] = V1[0] * V1[6] * V1[11] - V1[0] * V1[7] * V1[10] - V1[4] * V1[2] * V1[11] + V1[4] * V1[3] * V1[10] + V1[8] * V1[2] * V1[7] - V1[8] * V1[3] * V1[6];
1245 inv[11] = -V1[0] * V1[5] * V1[11] + V1[0] * V1[7] * V1[9] + V1[4] * V1[1] * V1[11] - V1[4] * V1[3] * V1[9] - V1[8] * V1[1] * V1[7] + V1[8] * V1[3] * V1[5];
1247 inv[15] = V1[0] * V1[5] * V1[10] - V1[0] * V1[6] * V1[9] - V1[4] * V1[1] * V1[10] + V1[4] * V1[2] * V1[9] + V1[8] * V1[1] * V1[6] - V1[8] * V1[2] * V1[5];
1249 det = V1[0] * inv[0] + V1[1] * inv[4] + V1[2] * inv[8] + V1[3] * inv[12];
1256 for (
int i = 0; i < 16; i++)
1257 invV1[i] = inv[i] * det;
1259 for (
int i = 0; i < 4; i++) {
1260 for (
int j = 0; j < 4; j++) {
1261 transform[j + i * 4] = 0.f;
1266 for (
int i = 0; i < 4; i++) {
1267 for (
int j = 0; j < 4; j++) {
1268 for (
int k = 0; k < 4; k++) {
1269 transform[j + i * 4] += V2[k + i * 4] * float(invV1[j + k * 4]);
1280 assert(color.r >= 0 && color.r <= 1 && color.g >= 0 && color.g <= 1 && color.b >= 0 && color.b <= 1);
1281 parent_object_ID = a_parent_objID;
1284 solid_fraction = 1.f;
1286 texturecoloroverridden =
false;
1290Patch::Patch(
const char *a_texturefile,
float a_solid_fraction,
uint a_parent_objID,
uint a_UUID) {
1293 parent_object_ID = a_parent_objID;
1296 texturefile = a_texturefile;
1297 solid_fraction = a_solid_fraction;
1298 texturecoloroverridden =
false;
1302Patch::Patch(
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv, std::map<std::string, Texture> &textures,
uint a_parent_objID,
uint a_UUID) {
1305 parent_object_ID = a_parent_objID;
1309 texturefile = a_texturefile;
1311 for (
auto &uv_vert: uv) {
1312 uv_vert.x = std::min(uv_vert.x, 1.f);
1313 uv_vert.y = std::min(uv_vert.y, 1.f);
1315 texturecoloroverridden =
false;
1317 solid_fraction = textures.at(texturefile).getSolidFraction(uv);
1322 const std::vector<vec3> &vertices = getVertices();
1323 float l = (vertices.at(1) - vertices.at(0)).magnitude();
1324 float w = (vertices.at(3) - vertices.at(0)).magnitude();
1329 return make_vec3(transform[3], transform[7], transform[11]);
1333 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1335 parent_object_ID = a_parent_objID;
1339 solid_fraction = 1.f;
1340 texturecoloroverridden =
false;
1344Triangle::Triangle(
const helios::vec3 &a_vertex0,
const helios::vec3 &a_vertex1,
const helios::vec3 &a_vertex2,
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv,
float solid_fraction,
uint a_parent_objID,
uint a_UUID) {
1345 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1347 parent_object_ID = a_parent_objID;
1351 texturefile = a_texturefile;
1353 this->solid_fraction = solid_fraction;
1354 texturecoloroverridden =
false;
1358Triangle::Triangle(
const helios::vec3 &a_vertex0,
const helios::vec3 &a_vertex1,
const helios::vec3 &a_vertex2,
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv, std::map<std::string, Texture> &textures,
uint a_parent_objID,
1360 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1362 parent_object_ID = a_parent_objID;
1366 texturefile = a_texturefile;
1368 for (
auto &uv_vert: uv) {
1369 uv_vert.x = std::min(uv_vert.x, 1.f);
1370 uv_vert.y = std::min(uv_vert.y, 1.f);
1372 solid_fraction = 1.f;
1373 texturecoloroverridden =
false;
1375 solid_fraction = textures.at(texturefile).getSolidFraction(uv);
1379vec3 Triangle::getVertex(
int vertex_index)
const {
1380 if (vertex_index < 0 || vertex_index > 2) {
1384 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
1388 vertex.
x = transform[0] * Y[vertex_index].x + transform[1] * Y[vertex_index].y + transform[2] * Y[vertex_index].z + transform[3];
1389 vertex.
y = transform[4] * Y[vertex_index].x + transform[5] * Y[vertex_index].y + transform[6] * Y[vertex_index].z + transform[7];
1390 vertex.
z = transform[8] * Y[vertex_index].x + transform[9] * Y[vertex_index].y + transform[10] * Y[vertex_index].z + transform[11];
1395vec3 Triangle::getCenter()
const {
1400 vec3 center0(1.f / 3.f, 2.f / 3.f, 0.f);
1403 center.
x = transform[0] * center0.x + transform[1] * center0.y + transform[2] * center0.z + transform[3];
1404 center.
y = transform[4] * center0.x + transform[5] * center0.y + transform[6] * center0.z + transform[7];
1405 center.
z = transform[8] * center0.x + transform[9] * center0.y + transform[10] * center0.z + transform[11];
1414 assert(color.r >= 0 && color.r <= 1 && color.g >= 0 && color.g <= 1 && color.b >= 0 && color.b <= 1);
1415 solid_fraction = 1.f;
1416 parent_object_ID = a_parent_objID;
1420 texturecoloroverridden =
false;
1424float Voxel::getVolume() {
1425 const vec3 &size = getSize();
1427 return size.
x * size.
y * size.
z;
1430vec3 Voxel::getCenter()
const {
1434 center.
x = transform[0] * Y.
x + transform[1] * Y.
y + transform[2] * Y.
z + transform[3];
1435 center.
y = transform[4] * Y.
x + transform[5] * Y.
y + transform[6] * Y.
z + transform[7];
1436 center.
z = transform[8] * Y.
x + transform[9] * Y.
y + transform[10] * Y.
z + transform[11];
1441vec3 Voxel::getSize()
const {
1442 vec3 n0(0, 0, 0), nx(1, 0, 0), ny(0, 1, 0), nz(0, 0, 1);
1443 vec3 n0_T, nx_T, ny_T, nz_T;
1450 float x = (nx_T - n0_T).magnitude();
1451 float y = (ny_T - n0_T).magnitude();
1452 float z = (nz_T - n0_T).magnitude();