1.3.49
 
Loading...
Searching...
No Matches
Context_primitive.cpp
Go to the documentation of this file.
1
16#include "Context.h"
17
18using namespace helios;
19
21 return addPatch(make_vec3(0, 0, 0), make_vec2(1, 1), make_SphericalCoord(0, 0), make_RGBAcolor(0, 0, 0, 1));
22}
23
24uint Context::addPatch(const vec3 &center, const vec2 &size) {
25 return addPatch(center, size, make_SphericalCoord(0, 0), make_RGBAcolor(0, 0, 0, 1));
26}
27
28uint Context::addPatch(const vec3 &center, const vec2 &size, const SphericalCoord &rotation) {
29 return addPatch(center, size, rotation, make_RGBAcolor(0, 0, 0, 1));
30}
31
32uint Context::addPatch(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBcolor &color) {
33 return addPatch(center, size, rotation, make_RGBAcolor(color, 1));
34}
35
36uint Context::addPatch(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBAcolor &color) {
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.");
39 }
40
41 auto *patch_new = (new Patch(color, 0, currentUUID));
42
43 // if( patch_new->getArea()==0 ){
44 // helios_runtime_error("ERROR (Context::addPatch): Patch has area of zero.");
45 // }
46
47 patch_new->scale(make_vec3(size.x, size.y, 1));
48
49 if (rotation.elevation != 0) {
50 patch_new->rotate(-rotation.elevation, "x");
51 }
52 if (rotation.azimuth != 0) {
53 patch_new->rotate(-rotation.azimuth, "z");
54 }
55
56 patch_new->translate(center);
57
58 primitives[currentUUID] = patch_new;
59 currentUUID++;
60 invalidateAllUUIDsCache();
61 return currentUUID - 1;
62}
63
64uint Context::addPatch(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const char *texture_file) {
65 addTexture(texture_file);
66
67 // Default (u, v) mapping
68 const std::vector<helios::vec2> uv = {{0.f, 0.f}, {1.f, 0.f}, {1.f, 1.f}, {0.f, 1.f}};
69
70 auto *patch_new = (new Patch(texture_file, uv, textures, 0, currentUUID));
71
72 // if( patch_new->getArea()==0 ){
73 // helios_runtime_error("ERROR (Context::addPatch): Patch has area of zero.");
74 // }
75
76 assert(size.x > 0.f && size.y > 0.f);
77 patch_new->scale(make_vec3(size.x, size.y, 1));
78
79 if (rotation.elevation != 0) {
80 patch_new->rotate(-rotation.elevation, "x");
81 }
82 if (rotation.azimuth != 0) {
83 patch_new->rotate(-rotation.azimuth, "z");
84 }
85
86 patch_new->translate(center);
87
88 primitives[currentUUID] = patch_new;
89 currentUUID++;
90 invalidateAllUUIDsCache();
91 return currentUUID - 1;
92}
93
94uint Context::addPatch(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const char *texture_file, const helios::vec2 &uv_center, const helios::vec2 &uv_size) {
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.");
97 }
98
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.");
101 }
102
103 addTexture(texture_file);
104
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)};
107
108 auto *patch_new = (new Patch(texture_file, uv, textures, 0, currentUUID));
109
110 // if( patch_new->getArea()==0 ){
111 // helios_runtime_error("ERROR (Context::addPatch): Patch has area of zero.");
112 // }
113
114 assert(size.x > 0.f && size.y > 0.f);
115 patch_new->scale(make_vec3(size.x, size.y, 1));
116
117 if (rotation.elevation != 0) {
118 patch_new->rotate(-rotation.elevation, "x");
119 }
120 if (rotation.azimuth != 0) {
121 patch_new->rotate(-rotation.azimuth, "z");
122 }
123
124 patch_new->translate(center);
125
126 primitives[currentUUID] = patch_new;
127 currentUUID++;
128 invalidateAllUUIDsCache();
129 return currentUUID - 1;
130}
131
132uint Context::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2) {
133 return addTriangle(vertex0, vertex1, vertex2, make_RGBAcolor(0, 0, 0, 1));
134}
135
136uint Context::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const RGBcolor &color) {
137 return addTriangle(vertex0, vertex1, vertex2, make_RGBAcolor(color, 1));
138}
139
140uint Context::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const RGBAcolor &color) {
141 auto *tri_new = (new Triangle(vertex0, vertex1, vertex2, color, 0, currentUUID));
142
143#ifdef HELIOS_DEBUG
144 if (calculateTriangleArea(vertex0, vertex1, vertex2) < 1e-10) {
145 std::cerr << "WARNING (Context::addTriangle): Triangle is malformed and has near-zero surface area." << std::endl;
146 }
147#endif
148
149 primitives[currentUUID] = tri_new;
150 currentUUID++;
151 invalidateAllUUIDsCache();
152 return currentUUID - 1;
153}
154
155uint Context::addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const char *texture_file, const helios::vec2 &uv0, const helios::vec2 &uv1, const helios::vec2 &uv2) {
156 addTexture(texture_file);
157
158 const std::vector<helios::vec2> uv{uv0, uv1, uv2};
159
160 auto *tri_new = (new Triangle(vertex0, vertex1, vertex2, texture_file, uv, textures, 0, currentUUID));
161
162#ifdef HELIOS_DEBUG
163 if (calculateTriangleArea(vertex0, vertex1, vertex2) < 1e-10) {
164 std::cerr << "WARNING (Context::addTriangle): Triangle is malformed and has near-zero surface area." << std::endl;
165 }
166#endif
167
168 primitives[currentUUID] = tri_new;
169 currentUUID++;
170 invalidateAllUUIDsCache();
171 return currentUUID - 1;
172}
173
174uint Context::addVoxel(const vec3 &center, const vec3 &size) {
175 return addVoxel(center, size, 0, make_RGBAcolor(0, 0, 0, 1));
176}
177
178uint Context::addVoxel(const vec3 &center, const vec3 &size, const float &rotation) {
179 return addVoxel(center, size, rotation, make_RGBAcolor(0, 0, 0, 1));
180}
181
182uint Context::addVoxel(const vec3 &center, const vec3 &size, const float &rotation, const RGBcolor &color) {
183 return addVoxel(center, size, rotation, make_RGBAcolor(color, 1));
184}
185
186uint Context::addVoxel(const vec3 &center, const vec3 &size, const float &rotation, const RGBAcolor &color) {
187 auto *voxel_new = (new Voxel(color, 0, currentUUID));
188
189 if (size.x * size.y * size.z == 0) {
190 helios_runtime_error("ERROR (Context::addVoxel): Voxel has size of zero.");
191 }
192
193 voxel_new->scale(size);
194
195 if (rotation != 0) {
196 voxel_new->rotate(rotation, "z");
197 }
198
199 voxel_new->translate(center);
200
201 primitives[currentUUID] = voxel_new;
202 currentUUID++;
203 invalidateAllUUIDsCache();
204 return currentUUID - 1;
205}
206
207void Context::translatePrimitive(uint UUID, const vec3 &shift) {
208 getPrimitivePointer_private(UUID)->translate(shift);
209}
210
211void Context::translatePrimitive(const std::vector<uint> &UUIDs, const vec3 &shift) {
212 float T[16];
213 makeTranslationMatrix(shift, T);
214
215 for (uint UUID: UUIDs) {
216 getPrimitivePointer_private(UUID)->applyTransform(T);
217 }
218}
219
220void Context::rotatePrimitive(uint UUID, float rotation_rad, const char *axis) {
221 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
222}
223
224void Context::rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const char *axis) {
225 if (rotation_rad == 0) {
226 return;
227 }
228
229 float T[16];
230 if (strcmp(axis, "z") == 0) {
231 makeRotationMatrix(rotation_rad, "z", T);
232 } else if (strcmp(axis, "y") == 0) {
233 makeRotationMatrix(rotation_rad, "y", T);
234 } else if (strcmp(axis, "x") == 0) {
235 makeRotationMatrix(rotation_rad, "x", T);
236 } else {
237 helios_runtime_error("ERROR (Context::rotatePrimitive): Rotation axis should be one of x, y, or z.");
238 }
239
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;
243 }
244 getPrimitivePointer_private(UUID)->applyTransform(T);
245 }
246}
247
248void Context::rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &axis) {
249 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
250}
251
252void Context::rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const vec3 &axis) {
253 if (rotation_rad == 0) {
254 return;
255 }
256
257 float T[16];
258 makeRotationMatrix(rotation_rad, axis, T);
259
260 for (uint UUID: UUIDs) {
261 if (getPrimitivePointer_private(UUID)->getType() == PRIMITIVE_TYPE_VOXEL) {
262 std::cerr << "WARNING (Context::rotatePrimitive): Voxels can only be rotate about the z-axis. Ignoring this rotation." << std::endl;
263 }
264 getPrimitivePointer_private(UUID)->applyTransform(T);
265 }
266}
267
268void Context::rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &origin, const helios::vec3 &axis) {
269 getPrimitivePointer_private(UUID)->rotate(rotation_rad, origin, axis);
270}
271
272void Context::rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const helios::vec3 &origin, const vec3 &axis) {
273 if (rotation_rad == 0) {
274 return;
275 }
276
277 float T[16];
278 makeRotationMatrix(rotation_rad, origin, axis, T);
279
280 for (uint UUID: UUIDs) {
281 if (getPrimitivePointer_private(UUID)->getType() == PRIMITIVE_TYPE_VOXEL) {
282 std::cerr << "WARNING (Context::rotatePrimitive): Voxels can only be rotate about the z-axis. Ignoring this rotation." << std::endl;
283 }
284 getPrimitivePointer_private(UUID)->applyTransform(T);
285 }
286}
287
288void Context::setPrimitiveNormal(uint UUID, const helios::vec3 &origin, const helios::vec3 &new_normal) {
289#ifdef HELIOS_DEBUG
290 if (!doesPrimitiveExist(UUID)) {
291 helios_runtime_error("ERROR (Context::setPrimitiveNormal): UUID of " + std::to_string(UUID) + " not found in the context.");
292 }
293#endif
294
295 auto *prim = getPrimitivePointer_private(UUID);
296
297 // old and new normals, unitized
298 helios::vec3 oldN = normalize(prim->getNormal());
299 helios::vec3 newN = normalize(new_normal);
300
301 // minimal rotation axis/angle
302 float d = std::clamp(oldN * newN, -1.f, 1.f);
303 float angle = acosf(d);
304 helios::vec3 axis = cross(oldN, newN);
305 if (axis.magnitude() < 1e-6f) {
306 axis = (std::fabs(oldN.x) < std::fabs(oldN.z)) ? cross(oldN, {1, 0, 0}) : cross(oldN, {0, 0, 1});
307 }
308 axis = axis.normalize();
309
310 // build M_delta about 'origin'
311 float M_delta[16];
312 makeRotationMatrix(angle, origin, axis, M_delta);
313
314 // grab existing world‐space model matrix
315 float M_old[16];
316 prim->getTransformationMatrix(M_old);
317
318 // preserve the rectangle's forward (local X) direction:
319 // - t0 is the world‐space image of (1,0,0) under M_old
320 helios::vec3 t0{
321 M_old[0], // row0·[1,0,0,0]
322 M_old[4], // row1·[1,0,0,0]
323 M_old[8] // row2·[1,0,0,0]
324 };
325 t0 = normalize(t0);
326
327 // apply M_delta to that direction (w=0)
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};
329 t1 = normalize(t1);
330
331 // desired forward is world‐X projected onto the new plane
332 helios::vec3 worldX{1.f, 0.f, 0.f};
333 helios::vec3 targ = worldX - newN * (newN * worldX);
334 targ = normalize(targ);
335
336 // compute the twist about newN that carries t1 → targ
337 // using signed angle in that plane
338 float twist = std::atan2(newN * cross(t1, targ), // dot(newN, t1×targ)
339 t1 * targ // dot(t1, targ)
340 );
341
342 // build that correction rotation
343 float M_twist[16];
344 makeRotationMatrix(twist, origin, newN, M_twist);
345
346 // now combine: M_new = M_twist * (M_delta * M_old)
347 float temp[16], M_new[16];
348 matmult(M_delta, M_old, temp);
349 matmult(M_twist, temp, M_new);
350
351 // write it back
352 prim->setTransformationMatrix(M_new);
353}
354
355void Context::setPrimitiveNormal(const std::vector<uint> &UUIDs, const helios::vec3 &origin, const vec3 &new_normal) {
356 for (uint UUID: UUIDs) {
357 setPrimitiveNormal(UUID, origin, new_normal);
358 }
359}
360
361void Context::setPrimitiveElevation(uint UUID, const vec3 &origin, float elevation_rad) {
362#ifdef HELIOS_DEBUG
363 if (!doesPrimitiveExist(UUID))
364 helios_runtime_error("setPrimitiveElevation: invalid UUID");
365#endif
366
367 // pull the existing normal
368 auto *prim = getPrimitivePointer_private(UUID);
369 vec3 oldN = prim->getNormal();
370
371 // convert to spherical coords, extract azimuth
372 SphericalCoord sc = cart2sphere(oldN);
373 float az = sc.azimuth;
374
375 // build the new unit‐normal with desired elevation, same azimuth
376 SphericalCoord targetSC(1.0f, elevation_rad, az);
377 vec3 targetN = sphere2cart(targetSC);
378
379 // delegate to your normal‐setting routine
380 setPrimitiveNormal(UUID, origin, targetN);
381}
382
383void Context::setPrimitiveAzimuth(uint UUID, const vec3 &origin, float azimuth_rad) {
384#ifdef HELIOS_DEBUG
385 if (!doesPrimitiveExist(UUID))
386 helios_runtime_error("setPrimitiveAzimuth: invalid UUID");
387#endif
388
389 // pull the existing normal
390 auto *prim = getPrimitivePointer_private(UUID);
391 vec3 oldN = prim->getNormal();
392
393 // convert to spherical coords, extract elevation
394 SphericalCoord sc = cart2sphere(oldN);
395 float elev = sc.elevation;
396
397 // build the new unit‐normal with same elevation, desired azimuth
398 SphericalCoord targetSC(1.0f, elev, azimuth_rad);
399 vec3 targetN = sphere2cart(targetSC);
400
401 // delegate to your normal‐setting routine
402 setPrimitiveNormal(UUID, origin, targetN);
403}
404
406#ifdef HELIOS_DEBUG
407 if (!doesPrimitiveExist(UUID)) {
408 helios_runtime_error("ERROR (Context::scalePrimitive): UUID of " + std::to_string(UUID) + " not found in the context.");
409 }
410#endif
411 if (S.x == 1 && S.y == 1 && S.z == 1) {
412 return;
413 }
414
415 float T[16];
416 makeScaleMatrix(S, T);
417
418 getPrimitivePointer_private(UUID)->applyTransform(T);
419}
420
421void Context::scalePrimitive(const std::vector<uint> &UUIDs, const helios::vec3 &S) {
422 for (uint UUID: UUIDs) {
423 scalePrimitive(UUID, S);
424 }
425}
426
428#ifdef HELIOS_DEBUG
429 if (!doesPrimitiveExist(UUID)) {
430 helios_runtime_error("ERROR (Context::scalePrimitiveAboutPoint): UUID of " + std::to_string(UUID) + " not found in the context.");
431 }
432#endif
433 if (S.x == 1 && S.y == 1 && S.z == 1) {
434 return;
435 }
436
437 getPrimitivePointer_private(UUID)->scale(S, point);
438}
439
440void Context::scalePrimitiveAboutPoint(const std::vector<uint> &UUIDs, const helios::vec3 &S, const helios::vec3 &point) {
441 for (uint UUID: UUIDs) {
442 scalePrimitiveAboutPoint(UUID, S, point);
443 }
444}
445
446void Context::deletePrimitive(const std::vector<uint> &UUIDs) {
447 for (uint UUID: UUIDs) {
448 deletePrimitive(UUID);
449 }
450}
451
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.");
455 }
456
457 Primitive *prim = primitives.at(UUID);
458
459 for (const auto &[label, type]: prim->primitive_data_types) {
460 decrementPrimitiveDataLabelCounter(label);
461 }
462
463 if (prim->getParentObjectID() != 0) { // primitive belongs to an object
464
465 uint ObjID = prim->getParentObjectID();
466 if (doesObjectExist(ObjID)) {
467 objects.at(ObjID)->deleteChildPrimitive(UUID);
468 if (getObjectPointer_private(ObjID)->getPrimitiveUUIDs().empty()) {
469 CompoundObject *obj = objects.at(ObjID);
470 delete obj;
471 objects.erase(ObjID);
472 }
473 }
474 }
475
476 delete prim;
477 primitives.erase(UUID);
478 dirty_deleted_primitives.push_back(UUID);
479 invalidateAllUUIDsCache();
480}
481
482std::vector<uint> Context::copyPrimitive(const std::vector<uint> &UUIDs) {
483 std::vector<uint> UUIDs_copy(UUIDs.size());
484 size_t i = 0;
485 for (uint UUID: UUIDs) {
486 UUIDs_copy.at(i) = copyPrimitive(UUID);
487 i++;
488 }
489
490 return UUIDs_copy;
491}
492
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.");
496 }
497
498 PrimitiveType type = primitives.at(UUID)->getType();
499 uint parentID = primitives.at(UUID)->getParentObjectID();
500 bool textureoverride = primitives.at(UUID)->isTextureColorOverridden();
501
502 if (type == PRIMITIVE_TYPE_PATCH) {
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);
507 Patch *patch_new;
508 if (!p->hasTexture()) {
509 patch_new = (new Patch(p->getColorRGBA(), parentID, currentUUID));
510 } else {
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);
515 } else {
516 patch_new = (new Patch(texture_file.c_str(), solid_fraction, parentID, currentUUID));
517 }
518 }
519 float transform[16];
520 p->getTransformationMatrix(transform);
521 patch_new->setTransformationMatrix(transform);
522 primitives[currentUUID] = patch_new;
523 } else if (type == PRIMITIVE_TYPE_TRIANGLE) {
524 Triangle *p = getTrianglePointer_private(UUID);
525 const std::vector<vec3> &vertices = p->getVertices();
526 const std::vector<vec2> &uv = p->getTextureUV();
527 Triangle *tri_new;
528 if (!p->hasTexture()) {
529 tri_new = (new Triangle(vertices.at(0), vertices.at(1), vertices.at(2), p->getColorRGBA(), parentID, currentUUID));
530 } else {
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);
535 }
536 float transform[16];
537 p->getTransformationMatrix(transform);
538 tri_new->setTransformationMatrix(transform);
539 primitives[currentUUID] = tri_new;
540 } else if (type == PRIMITIVE_TYPE_VOXEL) {
541 Voxel *p = getVoxelPointer_private(UUID);
542 Voxel *voxel_new;
543 // if( !p->hasTexture() ){
544 voxel_new = (new Voxel(p->getColorRGBA(), parentID, currentUUID));
545 //}else{
546 // voxel_new = (new Voxel( p->getColorRGBA(), currentUUID ));
547 /* \todo Texture-mapped voxels constructor here */
548 //}
549 float transform[16];
550 p->getTransformationMatrix(transform);
551 voxel_new->setTransformationMatrix(transform);
552 primitives[currentUUID] = voxel_new;
553 }
554
555 copyPrimitiveData(UUID, currentUUID);
556
557 if (textureoverride) {
558 getPrimitivePointer_private(currentUUID)->overrideTextureColor();
559 }
560
561 currentUUID++;
562 invalidateAllUUIDsCache();
563 return currentUUID - 1;
564}
565
566Primitive *Context::getPrimitivePointer_private(uint UUID) const {
567#ifdef HELIOS_DEBUG
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.");
570 }
571#endif
572 return primitives.at(UUID);
573}
574
576 return primitives.find(UUID) != primitives.end();
577}
578
579bool Context::doesPrimitiveExist(const std::vector<uint> &UUIDs) const {
580 if (UUIDs.empty()) {
581 return false;
582 }
583 for (uint UUID: UUIDs) {
584 if (!doesPrimitiveExist(UUID)) {
585 return false;
586 }
587 }
588 return true;
589}
590
591Patch *Context::getPatchPointer_private(uint UUID) const {
592#ifdef HELIOS_DEBUG
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.");
597 }
598#endif
599 return dynamic_cast<Patch *>(primitives.at(UUID));
600}
601
603#ifdef HELIOS_DEBUG
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.");
606 } else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_PATCH) {
607 helios_runtime_error("ERROR (Context::getPatchSize): UUID of " + std::to_string(UUID) + " is not a patch.");
608 }
609#endif
610 return dynamic_cast<Patch *>(primitives.at(UUID))->getSize();
611}
612
614#ifdef HELIOS_DEBUG
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.");
617 } else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_PATCH) {
618 helios_runtime_error("ERROR (Context::getPatchCenter): UUID of " + std::to_string(UUID) + " is not a patch.");
619 }
620#endif
621 return dynamic_cast<Patch *>(primitives.at(UUID))->getCenter();
622}
623
624Triangle *Context::getTrianglePointer_private(uint UUID) const {
625#ifdef HELIOS_DEBUG
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.");
630 }
631#endif
632 return dynamic_cast<Triangle *>(primitives.at(UUID));
633}
634
636#ifdef HELIOS_DEBUG
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.");
639 } else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_TRIANGLE) {
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.");
643 }
644#endif
645 return dynamic_cast<Triangle *>(primitives.at(UUID))->getVertex(number);
646}
647
648void Context::setTriangleVertices(uint UUID, const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2) {
649#ifdef HELIOS_DEBUG
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.");
652 }
653#endif
654 dynamic_cast<Triangle *>(primitives.at(UUID))->setVertices(vertex0, vertex1, vertex2);
655}
656
657Voxel *Context::getVoxelPointer_private(uint UUID) const {
658#ifdef HELIOS_DEBUG
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.");
663 }
664#endif
665 return dynamic_cast<Voxel *>(primitives.at(UUID));
666}
667
669#ifdef HELIOS_DEBUG
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.");
672 } else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_VOXEL) {
673 helios_runtime_error("ERROR (Context::getVoxelSize): UUID of " + std::to_string(UUID) + " is not a patch.");
674 }
675#endif
676 return dynamic_cast<Voxel *>(primitives.at(UUID))->getSize();
677}
678
680#ifdef HELIOS_DEBUG
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.");
683 } else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_VOXEL) {
684 helios_runtime_error("ERROR (Context::getVoxelCenter): UUID of " + std::to_string(UUID) + " is not a patch.");
685 }
686#endif
687 return dynamic_cast<Voxel *>(primitives.at(UUID))->getCenter();
688}
689
690size_t Context::getPrimitiveCount(bool include_hidden_primitives) const {
691 if (include_hidden_primitives) {
692 return primitives.size();
693 } else {
694 size_t count = 0;
695 for (const auto &[UUID, primitive]: primitives) {
696 if (!primitive->ishidden) {
697 count++;
698 }
699 }
700 return count;
701 }
702}
703
704size_t Context::getTriangleCount(bool include_hidden_primitives) const {
705 size_t count = 0;
706 for (const auto &[UUID, primitive]: primitives) {
707 if (primitive->getType() == PRIMITIVE_TYPE_TRIANGLE && (include_hidden_primitives || !primitive->ishidden)) {
708 count++;
709 }
710 }
711 return count;
712}
713
714size_t Context::getPatchCount(bool include_hidden_primitives) const {
715 size_t count = 0;
716 for (const auto &[UUID, primitive]: primitives) {
717 if (primitive->getType() == PRIMITIVE_TYPE_PATCH && (include_hidden_primitives || !primitive->ishidden)) {
718 count++;
719 }
720 }
721 return count;
722}
723
724// ===== PRIMITIVE, PATCH, TRIANGLE, AND VOXEL CLASS METHODS =====
725// Moved from Context.cpp
726
727Primitive::~Primitive() = default;
728
729uint Primitive::getUUID() const {
730 return UUID;
731}
732
733PrimitiveType Primitive::getType() const {
734 return prim_type;
735}
736
737void Primitive::setParentObjectID(uint objID) {
738 parent_object_ID = objID;
739}
740
741uint Primitive::getParentObjectID() const {
742 return parent_object_ID;
743}
744
745void Primitive::getTransformationMatrix(float (&T)[16]) const {
746 std::memcpy(T, transform, 16 * sizeof(float));
747}
748
749void Primitive::setTransformationMatrix(float (&T)[16]) {
750 std::memcpy(transform, T, 16 * sizeof(float));
751 dirty_flag = true;
752}
753
754float Patch::getArea() const {
755 const vec2 &size = getSize();
756
757 return size.x * size.y * solid_fraction;
758}
759
760float Triangle::getArea() const {
761 const std::vector<vec3> &vertices = getVertices();
762
763 float area = calculateTriangleArea(vertices[0], vertices[1], vertices[2]);
764
765 return area * solid_fraction;
766}
767
768float Voxel::getArea() const {
769 const vec3 size(transform[0], transform[5], transform[10]);
770
771 return 2.f * size.x * size.y + 2.f * size.x * size.z + 2.f * size.y * size.z;
772}
773
774vec3 Patch::getNormal() const {
775 return normalize(make_vec3(transform[2], transform[6], transform[10]));
776}
777
778vec3 Triangle::getNormal() const {
779 const std::vector<vec3> &vertices = getVertices();
780 return normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[1]));
781}
782
783vec3 Voxel::getNormal() const {
784 return nullorigin;
785}
786
787std::vector<vec3> Patch::getVertices() const {
788 std::vector<vec3> vertices(4);
789
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}};
791
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];
796 }
797 return vertices;
798}
799
800std::vector<vec3> Triangle::getVertices() const {
801 std::vector<vec3> vertices(3);
802
803 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
804
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];
809 }
810 return vertices;
811}
812
813std::vector<vec3> Voxel::getVertices() const {
814 std::vector<vec3> vertices(8);
815
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}};
817
818
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];
823 }
824 return vertices;
825}
826
827RGBcolor Primitive::getColor() const {
828 return {color.r, color.g, color.b};
829}
830
831RGBcolor Primitive::getColorRGB() const {
832 return {color.r, color.g, color.b};
833}
834
835RGBAcolor Primitive::getColorRGBA() const {
836 return color;
837}
838
839void Primitive::setColor(const helios::RGBcolor &newcolor) {
840 // if( parent_object_ID!=0 ){
841 // std::cout << "WARNING (Primitive::setColor): Cannot set the color of individual primitives within a compound object. Use the setter function for objects." << std::endl;
842 // return;
843 // }
844
845 color = make_RGBAcolor(newcolor, 1.f);
846 dirty_flag = true;
847}
848
849void Primitive::setColor(const helios::RGBAcolor &newcolor) {
850 // if( parent_object_ID!=0 ){
851 // std::cout << "WARNING (Primitive::setColor): Cannot set the color of individual primitives within a compound object. Use the setter function for objects." << std::endl;
852 // return;
853 // }
854
855 color = newcolor;
856 dirty_flag = true;
857}
858
859bool Primitive::hasTexture() const {
860 if (texturefile.empty()) {
861 return false;
862 } else {
863 return true;
864 }
865}
866
867std::string Primitive::getTextureFile() const {
868 return texturefile;
869}
870
871void Primitive::setTextureFile(const char *texture) {
872 texturefile = texture;
873 dirty_flag = true;
874}
875
876std::vector<vec2> Primitive::getTextureUV() {
877 return uv;
878}
879
880void Primitive::setTextureUV(const std::vector<vec2> &a_uv) {
881 uv = a_uv;
882 dirty_flag = true;
883}
884
885void Primitive::overrideTextureColor() {
886 // if( parent_object_ID!=0 ){
887 // std::cout << "WARNING (Primitive::overrideTextureColor): Cannot set the texture options of individual primitives within a compound object. Use the setter function for objects." << std::endl;
888 // return;
889 // }
890
891 texturecoloroverridden = true;
892 dirty_flag = true;
893}
894
895void Primitive::useTextureColor() {
896 // if( parent_object_ID!=0 ){
897 // std::cout << "WARNING (Primitive::useTextureColor): Cannot set the texture options of individual primitives within a compound object. Use the setter function for objects." << std::endl;
898 // return;
899 // }
900
901 texturecoloroverridden = false;
902 dirty_flag = true;
903}
904
905bool Primitive::isTextureColorOverridden() const {
906 return texturecoloroverridden;
907}
908
909float Primitive::getSolidFraction() const {
910 return solid_fraction;
911}
912
913void Primitive::setSolidFraction(float solidFraction) {
914 solid_fraction = solidFraction;
915 dirty_flag = true;
916}
917
918bool Triangle::edgeFunction(const helios::vec2 &a, const helios::vec2 &b, const helios::vec2 &c) {
919 return ((c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y) >= 0);
920}
921
922void Triangle::setVertices(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2) {
923 makeTransformationMatrix(vertex0, vertex1, vertex2);
924 dirty_flag = true;
925}
926
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;
930 return;
931 }
932
933 matmult(T, transform, transform);
934 dirty_flag = true;
935}
936
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;
940 return;
941 }
942 if (S.x == 0 || S.y == 0 || S.z == 0) {
943 helios_runtime_error("ERROR (Primitive::scale): Scaling factor cannot be zero.");
944 } else if (S.x == 1 && S.y == 1 && S.z == 1) {
945 return;
946 }
947
948 float T[16];
949 makeScaleMatrix(S, T);
950 matmult(T, transform, transform);
951 dirty_flag = true;
952}
953
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;
957 return;
958 }
959 if (S.x == 0 || S.y == 0 || S.z == 0) {
960 helios_runtime_error("ERROR (Primitive::scale): Scaling factor cannot be zero.");
961 } else if (S.x == 1 && S.y == 1 && S.z == 1) {
962 return;
963 }
964
965 float T[16];
966 makeScaleMatrix(S, point, T);
967 matmult(T, transform, transform);
968 dirty_flag = true;
969}
970
971void Primitive::translate(const helios::vec3 &shift) {
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;
974 return;
975 }
976
977 if (shift == nullorigin) {
978 return;
979 }
980
981 float T[16];
982 makeTranslationMatrix(shift, T);
983 matmult(T, transform, transform);
984 dirty_flag = true;
985}
986
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;
990 return;
991 }
992 if (rotation_radians == 0) {
993 return;
994 }
995
996 if (strcmp(rotation_axis_xyz_string, "z") == 0) {
997 float Rz[16];
998 makeRotationMatrix(rotation_radians, "z", Rz);
999 matmult(Rz, transform, transform);
1000 } else if (strcmp(rotation_axis_xyz_string, "y") == 0) {
1001 float Ry[16];
1002 makeRotationMatrix(rotation_radians, "y", Ry);
1003 matmult(Ry, transform, transform);
1004 } else if (strcmp(rotation_axis_xyz_string, "x") == 0) {
1005 float Rx[16];
1006 makeRotationMatrix(rotation_radians, "x", Rx);
1007 matmult(Rx, transform, transform);
1008 } else {
1009 helios_runtime_error("ERROR (Patch::rotate): Rotation axis should be one of x, y, or z.");
1010 }
1011 dirty_flag = true;
1012}
1013
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;
1017 return;
1018 }
1019 if (rotation_radians == 0) {
1020 return;
1021 }
1022
1023 float R[16];
1024 makeRotationMatrix(rotation_radians, rotation_axis_vector, R);
1025 matmult(R, transform, transform);
1026 dirty_flag = true;
1027}
1028
1029void Patch::rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) {
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;
1032 return;
1033 }
1034 if (rotation_radians == 0) {
1035 return;
1036 }
1037
1038 float R[16];
1039 makeRotationMatrix(rotation_radians, origin, rotation_axis_vector, R);
1040 matmult(R, transform, transform);
1041 dirty_flag = true;
1042}
1043
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;
1047 return;
1048 }
1049 if (rotation_radians == 0) {
1050 return;
1051 }
1052
1053 if (strcmp(rotation_axis_xyz_string, "z") == 0) {
1054 float Rz[16];
1055 makeRotationMatrix(rotation_radians, "z", Rz);
1056 matmult(Rz, transform, transform);
1057 } else if (strcmp(rotation_axis_xyz_string, "y") == 0) {
1058 float Ry[16];
1059 makeRotationMatrix(rotation_radians, "y", Ry);
1060 matmult(Ry, transform, transform);
1061 } else if (strcmp(rotation_axis_xyz_string, "x") == 0) {
1062 float Rx[16];
1063 makeRotationMatrix(rotation_radians, "x", Rx);
1064 matmult(Rx, transform, transform);
1065 } else {
1066 helios_runtime_error("ERROR (Triangle::rotate): Rotation axis should be one of x, y, or z.");
1067 }
1068 dirty_flag = true;
1069}
1070
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;
1074 return;
1075 }
1076 if (rotation_radians == 0) {
1077 return;
1078 }
1079
1080 float R[16];
1081 makeRotationMatrix(rotation_radians, rotation_axis_vector, R);
1082 matmult(R, transform, transform);
1083 dirty_flag = true;
1084}
1085
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;
1089 return;
1090 }
1091 if (rotation_radians == 0) {
1092 return;
1093 }
1094
1095 float R[16];
1096 makeRotationMatrix(rotation_radians, origin, rotation_axis_vector, R);
1097 matmult(R, transform, transform);
1098 dirty_flag = true;
1099}
1100
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;
1104 return;
1105 }
1106 if (rotation_radians == 0) {
1107 return;
1108 }
1109
1110 float Rz[16];
1111 makeRotationMatrix(rotation_radians, "z", Rz);
1112 matmult(Rz, transform, transform);
1113 dirty_flag = true;
1114}
1115
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;
1118}
1119
1120void Voxel::rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) {
1121 std::cerr << "WARNING (Voxel::rotate) - Voxels can only be rotated about the z-axis. Ignoring this call to rotate()." << std::endl;
1122}
1123
1124void Triangle::makeTransformationMatrix(const helios::vec3 &vert0, const helios::vec3 &vert1, const helios::vec3 &vert2) {
1125 // We need to construct the Affine transformation matrix that transforms some generic triangle to a triangle with vertices at vertex0, vertex1, vertex2.
1126
1127 // V1 is going to be our generic triangle. This is the triangle that we'll intersect in the OptiX ray intersection program. We just need to pass the transformation matrix to OptiX so that we'll end up with the right triangle.
1128
1129 // We'll assume our generic triangle has vertices
1130 // v0 = (0,0,0)
1131 // v1 = (0,1,0)
1132 // v2 = (1,1,0)
1133 // this needs to match up with the triangle in triangle_intersect() and triangle_bounds() (see primitiveIntersection.cu).
1134 // Note that the matrix is padded with 1's to make it 4x4
1135
1136 float V1[16];
1137
1138 /* [0,0] */
1139 V1[0] = 0.f;
1140 /* [0,1] */
1141 V1[1] = 0.f;
1142 /* [0,2] */
1143 V1[2] = 1.f;
1144
1145 /* [1,0] */
1146 V1[4] = 0.f;
1147 /* [1,1] */
1148 V1[5] = 1.f;
1149 /* [1,2] */
1150 V1[6] = 1.f;
1151
1152 /* [2,0] */
1153 V1[8] = 0.f;
1154 /* [2,1] */
1155 V1[9] = 0.f;
1156 /* [2,2] */
1157 V1[10] = 0.f;
1158
1159 /* [0,3] */
1160 V1[3] = 1.f;
1161 /* [1,3] */
1162 V1[7] = 1.f;
1163 /* [2,3] */
1164 V1[11] = 1.f;
1165 /* [3,0] */
1166 V1[12] = 1.f;
1167 /* [3,1] */
1168 V1[13] = 1.f;
1169 /* [3,2] */
1170 V1[14] = 1.f;
1171 /* [3,3] */
1172 V1[15] = 1.f;
1173
1174 // V2 holds the vertex locations we want to transform to
1175 // Note that the matrix is padded with 1's to make it 4x4
1176
1177 float V2[16];
1178 /* [0,0] */
1179 V2[0] = vert0.x;
1180 /* [0,1] */
1181 V2[1] = vert1.x;
1182 /* [0,2] */
1183 V2[2] = vert2.x;
1184 /* [0,3] */
1185 V2[3] = 1.f;
1186 /* [1,0] */
1187 V2[4] = vert0.y;
1188 /* [1,1] */
1189 V2[5] = vert1.y;
1190 /* [1,2] */
1191 V2[6] = vert2.y;
1192 /* [1,3] */
1193 V2[7] = 1.f;
1194 /* [2,0] */
1195 V2[8] = vert0.z;
1196 /* [2,1] */
1197 V2[9] = vert1.z;
1198 /* [2,2] */
1199 V2[10] = vert2.z;
1200 /* [2,3] */
1201 V2[11] = 1.f;
1202 /* [3,0] */
1203 V2[12] = 1.f;
1204 /* [3,1] */
1205 V2[13] = 1.f;
1206 /* [3,2] */
1207 V2[14] = 1.f;
1208 /* [3,3] */
1209 V2[15] = 1.f;
1210
1211 // Now we just need to solve the linear system for our transform matrix T
1212 // [T][V1] = [V2] -->
1213 // [T] = [V2]([V1]^-1)
1214
1215 double inv[16], det, invV1[16];
1216
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];
1218
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];
1220
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];
1222
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];
1224
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];
1226
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];
1228
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];
1230
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];
1232
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];
1234
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];
1236
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];
1238
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];
1240
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];
1242
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];
1244
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];
1246
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];
1248
1249 det = V1[0] * inv[0] + V1[1] * inv[4] + V1[2] * inv[8] + V1[3] * inv[12];
1250
1251 // if (det == 0)
1252 // return false;
1253
1254 det = 1.0 / det;
1255
1256 for (int i = 0; i < 16; i++)
1257 invV1[i] = inv[i] * det;
1258
1259 for (int i = 0; i < 4; i++) {
1260 for (int j = 0; j < 4; j++) {
1261 transform[j + i * 4] = 0.f;
1262 }
1263 }
1264
1265 // Multiply to get transformation matrix [T] = [V2]([V1]^-1)
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]);
1270 }
1271 }
1272 }
1273 dirty_flag = true;
1274}
1275
1276Patch::Patch(const RGBAcolor &a_color, uint a_parent_objID, uint a_UUID) {
1277 makeIdentityMatrix(transform);
1278
1279 color = a_color;
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;
1282 UUID = a_UUID;
1283 prim_type = PRIMITIVE_TYPE_PATCH;
1284 solid_fraction = 1.f;
1285 texturefile = "";
1286 texturecoloroverridden = false;
1287 dirty_flag = true;
1288}
1289
1290Patch::Patch(const char *a_texturefile, float a_solid_fraction, uint a_parent_objID, uint a_UUID) {
1291 makeIdentityMatrix(transform);
1292
1293 parent_object_ID = a_parent_objID;
1294 UUID = a_UUID;
1295 prim_type = PRIMITIVE_TYPE_PATCH;
1296 texturefile = a_texturefile;
1297 solid_fraction = a_solid_fraction;
1298 texturecoloroverridden = false;
1299 dirty_flag = true;
1300}
1301
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) {
1303 makeIdentityMatrix(transform);
1304
1305 parent_object_ID = a_parent_objID;
1306 UUID = a_UUID;
1307 prim_type = PRIMITIVE_TYPE_PATCH;
1308
1309 texturefile = a_texturefile;
1310 uv = a_uv;
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);
1314 }
1315 texturecoloroverridden = false;
1316
1317 solid_fraction = textures.at(texturefile).getSolidFraction(uv);
1318 dirty_flag = true;
1319}
1320
1321helios::vec2 Patch::getSize() const {
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();
1325 return {l, w};
1326}
1327
1328helios::vec3 Patch::getCenter() const {
1329 return make_vec3(transform[3], transform[7], transform[11]);
1330}
1331
1332Triangle::Triangle(const helios::vec3 &a_vertex0, const helios::vec3 &a_vertex1, const helios::vec3 &a_vertex2, const helios::RGBAcolor &a_color, uint a_parent_objID, uint a_UUID) {
1333 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1334 color = a_color;
1335 parent_object_ID = a_parent_objID;
1336 UUID = a_UUID;
1337 prim_type = PRIMITIVE_TYPE_TRIANGLE;
1338 texturefile = "";
1339 solid_fraction = 1.f;
1340 texturecoloroverridden = false;
1341 dirty_flag = true;
1342}
1343
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);
1346 color = make_RGBAcolor(RGB::red, 1);
1347 parent_object_ID = a_parent_objID;
1348 UUID = a_UUID;
1349 prim_type = PRIMITIVE_TYPE_TRIANGLE;
1350
1351 texturefile = a_texturefile;
1352 uv = a_uv;
1353 this->solid_fraction = solid_fraction;
1354 texturecoloroverridden = false;
1355 dirty_flag = true;
1356}
1357
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,
1359 uint a_UUID) {
1360 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1361 color = make_RGBAcolor(RGB::red, 1);
1362 parent_object_ID = a_parent_objID;
1363 UUID = a_UUID;
1364 prim_type = PRIMITIVE_TYPE_TRIANGLE;
1365
1366 texturefile = a_texturefile;
1367 uv = a_uv;
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);
1371 }
1372 solid_fraction = 1.f;
1373 texturecoloroverridden = false;
1374
1375 solid_fraction = textures.at(texturefile).getSolidFraction(uv);
1376 dirty_flag = true;
1377}
1378
1379vec3 Triangle::getVertex(int vertex_index) const {
1380 if (vertex_index < 0 || vertex_index > 2) {
1381 helios_runtime_error("ERROR (Context::getVertex): vertex index must be 1, 2, or 3.");
1382 }
1383
1384 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
1385
1386 vec3 vertex;
1387
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];
1391
1392 return vertex;
1393}
1394
1395vec3 Triangle::getCenter() const {
1396 // Y[0] = make_vec3( 0.f, 0.f, 0.f);
1397 // Y[1] = make_vec3( 0.f, 1.f, 0.f);
1398 // Y[2] = make_vec3( 1.f/3.f, 1.f, 0.f);
1399
1400 vec3 center0(1.f / 3.f, 2.f / 3.f, 0.f);
1401 vec3 center;
1402
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];
1406
1407 return center;
1408}
1409
1410Voxel::Voxel(const RGBAcolor &a_color, uint a_parent_objID, uint a_UUID) {
1411 makeIdentityMatrix(transform);
1412
1413 color = a_color;
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;
1417 UUID = a_UUID;
1418 prim_type = PRIMITIVE_TYPE_VOXEL;
1419 texturefile = "";
1420 texturecoloroverridden = false;
1421 dirty_flag = true;
1422}
1423
1424float Voxel::getVolume() {
1425 const vec3 &size = getSize();
1426
1427 return size.x * size.y * size.z;
1428}
1429
1430vec3 Voxel::getCenter() const {
1431 vec3 center;
1432 vec3 Y;
1433
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];
1437
1438 return center;
1439}
1440
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;
1444
1445 vecmult(transform, n0, n0_T);
1446 vecmult(transform, nx, nx_T);
1447 vecmult(transform, ny, ny_T);
1448 vecmult(transform, nz, nz_T);
1449
1450 float x = (nx_T - n0_T).magnitude();
1451 float y = (ny_T - n0_T).magnitude();
1452 float z = (nz_T - n0_T).magnitude();
1453
1454 return {x, y, z};
1455}