1.3.64
 
Loading...
Searching...
No Matches
CollisionDetection_Slicing.cpp
Go to the documentation of this file.
1
16#include "CollisionDetection.h"
17
18using namespace helios;
19
20// -------- GEOMETRIC UTILITY FUNCTIONS --------
21
22helios::vec3 CollisionDetection::linesIntersection(const helios::vec3 &line1_point, const helios::vec3 &line1_direction, const helios::vec3 &line2_point, const helios::vec3 &line2_direction) const {
23
24 helios::vec3 g = line2_point - line1_point;
25 helios::vec3 h = cross(line2_direction, g);
26 helios::vec3 k = cross(line2_direction, line1_direction);
27
28 float h_mag = sqrt(pow(h.x, 2) + pow(h.y, 2) + pow(h.z, 2));
29 float k_mag = sqrt(pow(k.x, 2) + pow(k.y, 2) + pow(k.z, 2));
30
31 // in the same direction
32 if (((h.x >= 0 && k.x >= 0) || (h.x < 0 && k.x < 0)) && ((h.y >= 0 && k.y >= 0) || (h.y < 0 && k.y < 0)) && ((h.z >= 0 && k.z >= 0) || (h.z < 0 && k.z < 0))) {
33 helios::vec3 rht = (h_mag / k_mag) * line1_direction;
34 return line1_point + rht;
35 } else { // different direction
36 helios::vec3 rht = (h_mag / k_mag) * line1_direction;
37 return line1_point - rht;
38 }
39}
40
41bool CollisionDetection::approxSame(float a, float b, float absTol, float relTol) const {
42 return fabs(a - b) <= absTol || fabs(a - b) <= relTol * (std::max(fabs(a), fabs(b)));
43}
44
45bool CollisionDetection::approxSame(const helios::vec3 &a, const helios::vec3 &b, float absTol) const {
46 return fabs(a.x - b.x) <= absTol && fabs(a.y - b.y) <= absTol && fabs(a.z - b.z) <= absTol;
47}
48
50 // uv coordinate that will be output
51 helios::vec2 uvs;
52
53 float Dxyz = sqrtf(powf(p2.x - p1.x, 2.0) + powf(p2.y - p1.y, 2.0) + powf(p2.z - p1.z, 2.0)); // distance between edge vertex xyz coordinates
54 float Duv = sqrtf(powf(uv2.x - uv1.x, 2.0) + powf(uv2.y - uv1.y, 2.0)); // distance between edge vertex uv coordinates
55 float Dxyzs = sqrtf(powf(ps.x - p1.x, 2.0) + powf(ps.y - p1.y, 2.0) + powf(ps.z - p1.z, 2.0)); // distance between slice point and first vertex xyz coordinates
56
57 float absTol = pow(10, -6);
58
59 float F = (Dxyzs / Dxyz);
60 if (F > 1.0) {
61 helios_runtime_error("ERROR (CollisionDetection::interpolate_texture_UV_to_slice_point): slice point is not between the two end points.");
62 } else if (approxSame(p1, ps, absTol)) {
63 // then the slice point is the same as the first vertex
64 uvs = make_vec2(uv1.x, uv1.y);
65 return uvs;
66 } else if (approxSame(p2, ps, absTol)) {
67 // then the slice point is the same as the second vertex
68 uvs = make_vec2(uv2.x, uv2.y);
69 return uvs;
70 }
71
72 // if the u coordinates of the two vertices are the same
73 if (uv2.x == uv1.x) {
74 std::vector<float> vec_uv;
75 vec_uv.push_back(uv1.y);
76 vec_uv.push_back(uv2.y);
77 uvs = make_vec2(uv1.x, min(vec_uv) + Duv * (Dxyzs / Dxyz));
78
79 } else {
80
81 // equation for the line between uv coordinates of the two vertices
82 float slope = (uv2.y - uv1.y) / (uv2.x - uv1.x);
83 float offset = uv1.y - slope * uv1.x;
84
85 // coefficients of the quadratic equation for the u coordinate of the slice point
86 float a = powf(slope, 2.0) + 1.0;
87 float b = -2.0 * uv1.x + 2.0 * slope * offset - 2.0 * slope * uv1.y;
88 float c = (powf(uv1.x, 2.0) + powf(offset, 2.0) - 2.0 * offset * uv1.y + powf(uv1.y, 2.0)) - powf((Dxyzs / Dxyz) * Duv, 2.0);
89
90 // solve the quadratic
91 float us_a = (-1.0 * b + sqrtf(powf(b, 2.0) - 4.0 * a * c)) / (2.0 * a);
92 float us_b = (-1.0 * b - sqrtf(powf(b, 2.0) - 4.0 * a * c)) / (2.0 * a);
93 // get the v coordinate
94 float vs_a = slope * us_a + offset;
95 float vs_b = slope * us_b + offset;
96
97 // determine which of the roots is the right one
98 if (((us_a >= uv1.x && us_a <= uv2.x) || (us_a <= uv1.x && us_a >= uv2.x)) && ((vs_a >= uv1.y && vs_a <= uv2.y) || (vs_a <= uv1.y && vs_a >= uv2.y))) {
99 uvs = make_vec2(us_a, vs_a);
100
101 } else if (((us_b >= uv1.x && us_b <= uv2.x) || (us_b <= uv1.x && us_b >= uv2.x)) && ((vs_b >= uv1.y && vs_b <= uv2.y) || (vs_b <= uv1.y && vs_b >= uv2.y))) {
102 uvs = make_vec2(us_b, vs_b);
103
104 } else {
105 helios_runtime_error("ERROR (CollisionDetection::interpolate_texture_UV_to_slice_point): could not interpolate UV coordinates.");
106 }
107 }
108
109 return uvs;
110}
111
112// -------- PRIMITIVE SLICING FUNCTIONS --------
113
114std::vector<uint> CollisionDetection::slicePrimitive(uint UUID, const std::vector<helios::vec3> &voxel_face_vertices, helios::WarningAggregator &warnings) {
115
116 // vector of UUIDs that will be output
117 std::vector<uint> resulting_UUIDs;
118
119 if (voxel_face_vertices.size() < 3) {
120 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): voxel_face_vertices must contain at least three points.");
121 }
122
123 helios::vec3 face_normal = cross(voxel_face_vertices.at(1) - voxel_face_vertices.at(0), voxel_face_vertices.at(2) - voxel_face_vertices.at(1));
124 face_normal.normalize();
125
126 std::vector<helios::vec3> primitive_vertices = this->context->getPrimitiveVertices(UUID);
127 helios::vec3 primitive_normal = this->context->getPrimitiveNormal(UUID);
128 primitive_normal.normalize();
129
130 helios::RGBAcolor primitive_color = this->context->getPrimitiveColorRGBA(UUID);
131
132 std::string texa;
133 const char *tex;
134 texa = this->context->getPrimitiveTextureFile(UUID);
135 tex = texa.c_str();
136 bool primitiveHasTexture = !texa.empty();
137
138 // get the area of the original primitive for comparison with the area of the sliced primitives later
139 float original_area = this->context->getPrimitiveArea(UUID);
140
142 // find the equation of the line where the planes of the patch and voxel face intersect
143
144 // direction of the plane intersection line
145 helios::vec3 direction_vector = cross(face_normal, primitive_normal);
146
147 // find a point on the plane intersection line
148 // based on https://vicrucann.github.io/tutorials/3d-geometry-algorithms/
149 helios::vec3 a = helios::make_vec3(fabs(direction_vector.x), fabs(direction_vector.y), fabs(direction_vector.z));
150 uint maxc;
151 if (a.x > a.y) {
152 if (a.x > a.z) {
153 maxc = 1;
154 } else {
155 maxc = 3;
156 }
157 } else {
158 if (a.y > a.z) {
159 maxc = 2;
160 } else {
161 maxc = 3;
162 }
163 }
164
165 helios::vec3 d1a = helios::make_vec3(-1 * face_normal.x * voxel_face_vertices.at(0).x, -1 * face_normal.y * voxel_face_vertices.at(0).y, -1 * face_normal.z * voxel_face_vertices.at(0).z);
166 helios::vec3 d2a = helios::make_vec3(-1 * primitive_normal.x * primitive_vertices.at(1).x, -1 * primitive_normal.y * primitive_vertices.at(1).y, -1 * primitive_normal.z * primitive_vertices.at(1).z);
167
168 float d1 = d1a.x + d1a.y + d1a.z;
169 float d2 = d2a.x + d2a.y + d2a.z;
170
171 float xi;
172 float yi;
173 float zi;
174
175 if (maxc == 1) {
176 xi = 0;
177 yi = (d2 * face_normal.z - d1 * primitive_normal.z) / direction_vector.x;
178 zi = (d1 * primitive_normal.y - d2 * face_normal.y) / direction_vector.x;
179 } else if (maxc == 2) {
180 xi = (d1 * primitive_normal.z - d2 * face_normal.z) / direction_vector.y;
181 yi = 0;
182 zi = (d2 * face_normal.x - d1 * primitive_normal.x) / direction_vector.y;
183 } else if (maxc == 3) {
184 xi = (d2 * face_normal.y - d1 * primitive_normal.y) / direction_vector.z;
185 yi = (d1 * primitive_normal.x - d2 * face_normal.x) / direction_vector.z;
186 zi = 0;
187 }
188
189 helios::vec3 ipoint = make_vec3(xi, yi, zi);
190
192 // get points of intersection between each edge of the patch and the patch-voxel intersection line
193
194 // vector for points of intersection between edge line and intersection line
195 std::vector<helios::vec3> possible_points;
196 // vector for points that actually touch the patch
197 std::vector<helios::vec3> slice_points;
198 std::vector<uint> slice_points_edge_ID;
199 uint vertex_index; // index for cases where one slice point is on a vertex (used for patch cases only)
200
201 helios::vec3 vi0;
202 helios::vec3 vi1;
203
204 // go through the different edges of the patch and calculate intersection points with line along edge of patch and intersection line
205 if (primitive_vertices.size() == 4) {
206 possible_points.resize(4);
207 possible_points.at(0) = linesIntersection(primitive_vertices.at(1), primitive_vertices.at(1) - primitive_vertices.at(0), ipoint, direction_vector);
208 possible_points.at(1) = linesIntersection(primitive_vertices.at(2), primitive_vertices.at(2) - primitive_vertices.at(1), ipoint, direction_vector);
209 possible_points.at(2) = linesIntersection(primitive_vertices.at(3), primitive_vertices.at(3) - primitive_vertices.at(2), ipoint, direction_vector);
210 possible_points.at(3) = linesIntersection(primitive_vertices.at(0), primitive_vertices.at(0) - primitive_vertices.at(3), ipoint, direction_vector);
211
212 for (uint i = 0; i < 4; i++) {
213 if (i == 0) {
214 vi1 = primitive_vertices.at(1);
215 vi0 = primitive_vertices.at(0);
216 } else if (i == 1) {
217 vi1 = primitive_vertices.at(2);
218 vi0 = primitive_vertices.at(1);
219 } else if (i == 2) {
220 vi1 = primitive_vertices.at(3);
221 vi0 = primitive_vertices.at(2);
222 } else if (i == 3) {
223 vi1 = primitive_vertices.at(0);
224 vi0 = primitive_vertices.at(3);
225 }
226
227 bool test_x = ((possible_points.at(i).x >= vi1.x && possible_points.at(i).x <= vi0.x) || (possible_points.at(i).x >= vi0.x && possible_points.at(i).x <= vi1.x));
228 bool test_y = ((possible_points.at(i).y >= vi1.y && possible_points.at(i).y <= vi0.y) || (possible_points.at(i).y >= vi0.y && possible_points.at(i).y <= vi1.y));
229 bool test_z = ((possible_points.at(i).z >= vi1.z && possible_points.at(i).z <= vi0.z) || (possible_points.at(i).z >= vi0.z && possible_points.at(i).z <= vi1.z));
230
231 if (test_x && test_y && test_z) {
232 slice_points.push_back(possible_points.at(i));
233 slice_points_edge_ID.push_back(i);
234 }
235 }
236
237 } else if (primitive_vertices.size() == 3) {
238
239 possible_points.resize(3);
240 possible_points.at(0) = linesIntersection(primitive_vertices.at(1), primitive_vertices.at(1) - primitive_vertices.at(0), ipoint, direction_vector);
241 possible_points.at(1) = linesIntersection(primitive_vertices.at(2), primitive_vertices.at(2) - primitive_vertices.at(1), ipoint, direction_vector);
242 possible_points.at(2) = linesIntersection(primitive_vertices.at(0), primitive_vertices.at(0) - primitive_vertices.at(2), ipoint, direction_vector);
243
244 for (uint i = 0; i < 3; i++) {
245 if (i == 0) {
246 vi1 = primitive_vertices.at(1);
247 vi0 = primitive_vertices.at(0);
248 } else if (i == 1) {
249 vi1 = primitive_vertices.at(2);
250 vi0 = primitive_vertices.at(1);
251
252 } else if (i == 2) {
253 vi1 = primitive_vertices.at(0);
254 vi0 = primitive_vertices.at(2);
255 }
256
257 bool test_x = ((possible_points.at(i).x >= vi1.x && possible_points.at(i).x <= vi0.x) || (possible_points.at(i).x >= vi0.x && possible_points.at(i).x <= vi1.x));
258 bool test_y = ((possible_points.at(i).y >= vi1.y && possible_points.at(i).y <= vi0.y) || (possible_points.at(i).y >= vi0.y && possible_points.at(i).y <= vi1.y));
259 bool test_z = ((possible_points.at(i).z >= vi1.z && possible_points.at(i).z <= vi0.z) || (possible_points.at(i).z >= vi0.z && possible_points.at(i).z <= vi1.z));
260
261 if (test_x && test_y && test_z) {
262 slice_points.push_back(possible_points.at(i));
263 slice_points_edge_ID.push_back(i);
264 }
265 }
266 }
267
268
269 // can be 0, 1, 2, 3, or 4 (0 and 2 are most common)
270 uint initial_slice_points_size = slice_points.size();
271 // std::cout << "initial_slice_points_size = " << initial_slice_points_size << std::endl;
272
273 float absTol = pow(10, -6);
274 float relTol = pow(10, -20);
275
276
277 // the primitive did not intersect with the voxel face
278 if (initial_slice_points_size == 0) {
279 resulting_UUIDs.push_back(UUID);
280 return resulting_UUIDs;
281
282 } else if (initial_slice_points_size == 1) {
283 // the primitive intersected with the face at a single point (a corner) - no slicing needed
284 resulting_UUIDs.push_back(UUID);
285 if (this->printmessages) {
286 std::cout << "the primitive intersected with the face at a single point (a corner) - no slicing needed" << std::endl;
287 }
288 return resulting_UUIDs;
289 } else if (initial_slice_points_size == 2) {
290
291 // This is the usual case
292 // just check to see if the two slice points are approximately at two vertices for edge cases here
293
294 // the primitive intersected with the face along an edge - no need to slice
295 if (slice_points_edge_ID.at(0) == slice_points_edge_ID.at(1)) {
296 resulting_UUIDs.push_back(UUID);
297 if (this->printmessages) {
298 std::cout << "the primitive intersected with the face along an edge - no need to slice" << std::endl;
299 }
300 return resulting_UUIDs;
301 }
302
303 if (primitive_vertices.size() == 4) {
304 if ((approxSame(slice_points.at(0), primitive_vertices.at(0), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(1), absTol)) ||
305 (approxSame(slice_points.at(0), primitive_vertices.at(1), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(0), absTol)) ||
306 (approxSame(slice_points.at(0), primitive_vertices.at(1), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(2), absTol)) ||
307 (approxSame(slice_points.at(0), primitive_vertices.at(2), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(1), absTol)) ||
308 (approxSame(slice_points.at(0), primitive_vertices.at(2), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(3), absTol)) ||
309 (approxSame(slice_points.at(0), primitive_vertices.at(3), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(2), absTol)) ||
310 (approxSame(slice_points.at(0), primitive_vertices.at(3), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(0), absTol)) ||
311 (approxSame(slice_points.at(0), primitive_vertices.at(0), absTol) && approxSame(slice_points.at(1), primitive_vertices.at(3), absTol))) {
312 if (this->printmessages) {
313 std::cout << "the primitive intersected with the face along an edge - no need to slice" << std::endl;
314 }
315 resulting_UUIDs.push_back(UUID);
316 return resulting_UUIDs;
317 }
318
319 } else if (primitive_vertices.size() == 3) {
320
321 if ((approxSame(slice_points.at(0), primitive_vertices.at(0), absTol) || approxSame(slice_points.at(0), primitive_vertices.at(1), absTol) || approxSame(slice_points.at(0), primitive_vertices.at(2), absTol)) &&
322 (approxSame(slice_points.at(1), primitive_vertices.at(0), absTol) || approxSame(slice_points.at(1), primitive_vertices.at(1), absTol) || approxSame(slice_points.at(1), primitive_vertices.at(2), absTol))) {
323 resulting_UUIDs.push_back(UUID);
324 if (this->printmessages) {
325 std::cout << "the primitive intersected with the face along an edge - no need to slice" << std::endl;
326 }
327 return resulting_UUIDs;
328 }
329 }
330
331
332 // now that edge cases are taken care of,
333 // for each slice point, if it is approximately the same as a vertex, set it to that vertex
334 for (uint j = 0; j < primitive_vertices.size(); j++) {
335 for (uint i = 0; i < slice_points.size(); i++) {
336 // distance between slice point and primitive vertex
337 float Dxyza = sqrtf(powf(primitive_vertices.at(j).x - slice_points.at(i).x, 2.0) + powf(primitive_vertices.at(j).y - slice_points.at(i).y, 2.0) + powf(primitive_vertices.at(j).z - slice_points.at(i).z, 2.0));
338 if (approxSame(Dxyza, float(0.0), absTol, relTol)) {
339 slice_points.at(i) = primitive_vertices.at(j);
340 }
341 }
342 }
343
344
345 } else if (initial_slice_points_size == 3) {
346
347 // if there are 3 slice points, this probably means that two of the points are very close to each other,
348 // at or approximately at one of the primitive's vertices
349 // in this case, if the primitive is a triangle, then it should be sliced into two triangles, not the usual three
350 // in case the primitive is a patch, then it should be sliced into 3 triangles if this occurs at only one vertex
351
352 vec3 non_vertex_slice_point;
353 uint non_vertex_slice_edge_ID;
354 vec3 vertex_slice_point;
355
356 for (uint bb = 0; bb < slice_points.size(); bb++) {
357 bool this_point_vert_test = false;
358 for (uint cc = 0; cc < primitive_vertices.size(); cc++) {
359 bool vert_test = approxSame(slice_points.at(bb), primitive_vertices.at(cc), absTol);
360 // std::cout << "-- test = " << vert_test <<" -- slice point " << bb << " = " << slice_points.at(bb) << ", primitive_vertex " << cc << " = " << primitive_vertices.at(cc) << std::endl;
361 if (vert_test) {
362 this_point_vert_test = true;
363 vertex_slice_point = primitive_vertices.at(cc);
364 vertex_index = cc;
365 }
366 }
367
368 if (this_point_vert_test == false) {
369 non_vertex_slice_point = slice_points.at(bb);
370 non_vertex_slice_edge_ID = slice_points_edge_ID.at(bb);
371 }
372 }
373 slice_points.resize(2);
374 slice_points.at(0) = non_vertex_slice_point;
375 slice_points_edge_ID.at(0) = non_vertex_slice_edge_ID;
376 slice_points.at(1) = vertex_slice_point;
377
378 // std::cout << "slice_points.at(0) = " << slice_points.at(0) << std::endl;
379 // std::cout << "slice_points.at(1) = " << slice_points.at(1) << std::endl;
380 // std::cout << "slice_points_edge_ID.at(0) = " << slice_points_edge_ID.at(0) << std::endl;
381 // std::cout << "vertex_index = " << vertex_index << std::endl;
382
383 } else if (initial_slice_points_size == 4) {
384 // if the voxel face splits a patch diagonally, then only 2 triangles should be produced instead of the usual four
385 vec3 non_vertex_slice_point;
386 uint non_vertex_slice_edge_ID;
387 vec3 vertex_slice_point;
388 for (uint bb = 0; bb < slice_points.size(); bb++) {
389 bool this_point_vert_test = false;
390 for (uint cc = 0; cc < primitive_vertices.size(); cc++) {
391 bool vert_test = approxSame(slice_points.at(bb), primitive_vertices.at(cc), absTol);
392 // std::cout << "-- test = " << vert_test <<" -- slice point " << bb << " = " << slice_points.at(bb) << ", primitive_vertex " << cc << " = " << primitive_vertices.at(cc) << std::endl;
393 if (vert_test) {
394 this_point_vert_test = true;
395 vertex_index = cc;
396 }
397 }
398 }
399 slice_points.resize(2);
400 } else {
401 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): more than 5 slice points detected - invalid geometry.");
402 }
403
404 // determine which side of the plane vertex 0 is on and use that to determine the sign of the buffer to add to the face coordinate
405 // the buffer ensures that the vertices will be categorized into grid cells correctly
406 // note that some of these checks are based on the assumption of a axis aligned grid - would need to be re-worked if implementing rotated grid
407
408 helios::vec3 face_coordinate = make_vec3(fabs(face_normal.x) * voxel_face_vertices.at(0).x, fabs(face_normal.y) * voxel_face_vertices.at(0).y, fabs(face_normal.z) * voxel_face_vertices.at(0).z);
409 // float buffer_value = powf(float(10), float(-6));
410 float buffer_value = powf(float(10), float(-5));
411 helios::vec3 buffer = make_vec3(0, 0, 0);
412 if (fabs(face_normal.x) > 0.5) {
413 if (primitive_vertices.at(0).x < face_coordinate.x) {
414 buffer = make_vec3(float(-1) * buffer_value, 0, 0);
415 } else if (primitive_vertices.at(0).x > face_coordinate.x) {
416 buffer = make_vec3(buffer_value, 0, 0);
417 } else {
418 if (this->printmessages) {
419 std::cout << "vertex 0 exactly at face" << std::endl;
420 }
421 }
422
423 } else if (fabs(face_normal.y) > 0.5) {
424 if (primitive_vertices.at(0).y < face_coordinate.y) {
425 buffer = make_vec3(0, float(-1) * buffer_value, 0);
426 } else if (primitive_vertices.at(0).y > face_coordinate.y) {
427 buffer = make_vec3(0, buffer_value, 0);
428 } else {
429 if (this->printmessages) {
430 std::cout << "vertex 0 exactly at face" << std::endl;
431 }
432 }
433
434 } else if (fabs(face_normal.z) > 0.5) {
435 if (primitive_vertices.at(0).z < face_coordinate.z) {
436 buffer = make_vec3(0, 0, float(-1) * buffer_value);
437 } else if (primitive_vertices.at(0).z > face_coordinate.z) {
438 buffer = make_vec3(0, 0, buffer_value);
439 } else {
440 if (this->printmessages) {
441 std::cout << "vertex 0 exactly at face" << std::endl;
442 }
443 }
444 }
445
446 // UUIDs for triangles to be created below
447 uint t0;
448 uint t1;
449 uint t2;
450 uint t3;
451
452 // if a resulting triangle area is below this value, delete it
453 float minArea = pow(10, -13);
454
455 // use this diagnostic code to locate where a particular triangle is being created
456 // (uncomment the print out far below)
457 uint diag_1 = 0;
458
460 // if the primitive isn't texture masked
461 if (primitiveHasTexture == false) {
462
463 if (primitive_vertices.size() == 3) {
464 // split into three triangles (usual case)
465 if (initial_slice_points_size == 2) {
466 if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 1)) {
467 diag_1 = 1;
468 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, primitive_color);
469 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_color);
470 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
471 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 0)) {
472 diag_1 = 2;
473 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_color);
474 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, slice_points.at(1) + buffer, primitive_color);
475 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_color);
476 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 2)) {
477 diag_1 = 3;
478 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
479 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
480 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
481 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 0)) {
482 diag_1 = 4;
483 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
484 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
485 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
486 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 2)) {
487 diag_1 = 5;
488 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color); //
489 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color); //
490 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
491 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 1)) {
492 diag_1 = 6;
493 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color); //
494 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color); //
495 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
496 }
497
498 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
499 if (this->context->getPrimitiveArea(t0) < minArea) {
500 this->context->deletePrimitive(t0);
501 } else {
502 resulting_UUIDs.push_back(t0);
503 }
504 if (this->context->getPrimitiveArea(t1) < minArea) {
505 this->context->deletePrimitive(t1);
506 } else {
507 resulting_UUIDs.push_back(t1);
508 }
509 if (this->context->getPrimitiveArea(t2) < minArea) {
510 this->context->deletePrimitive(t2);
511 } else {
512 resulting_UUIDs.push_back(t2);
513 }
514
515
516 } else if (initial_slice_points_size == 3) {
517 // split into two triangles instead of three since a vertex falls on the slicing face
518
519 if (slice_points_edge_ID.at(0) == 0) {
520 diag_1 = 7;
521 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
522 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, primitive_color);
523 } else if (slice_points_edge_ID.at(0) == 1) {
524 diag_1 = 8;
525 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, slice_points.at(1) + buffer, primitive_color);
526 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_color);
527 } else if (slice_points_edge_ID.at(0) == 2) {
528 diag_1 = 9;
529 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
530 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
531 }
532
533 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
534 if (this->context->getPrimitiveArea(t0) < minArea) {
535 this->context->deletePrimitive(t0);
536 } else {
537 resulting_UUIDs.push_back(t0);
538 }
539 if (this->context->getPrimitiveArea(t1) < minArea) {
540 this->context->deletePrimitive(t1);
541 } else {
542 resulting_UUIDs.push_back(t1);
543 }
544 }
545
546 } else if (primitive_vertices.size() == 4) {
547
548 // split into four triangles (usual case)
549 if (initial_slice_points_size == 2) {
550 // cases where intersection points are on opposite sides
551 if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 2)) {
552 diag_1 = 10;
553 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
554 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
555 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
556 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
557
558
559 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 0)) {
560 diag_1 = 11;
561 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
562 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
563 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
564 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
565
566 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 3)) {
567 diag_1 = 12;
568 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
569 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(3) - buffer, slice_points.at(1) - buffer, primitive_color);
570 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
571 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
572
573 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 1)) {
574 diag_1 = 13;
575 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, slice_points.at(1) + buffer, primitive_color);
576 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
577 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
578 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
579
580 // cases where intersection points are on adjacent sides
581 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 3)) {
582 diag_1 = 14;
583 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
584 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
585 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
586 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
587 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 0)) {
588 diag_1 = 15;
589 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
590 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
591 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
592 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
593
594 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 1)) {
595 diag_1 = 16;
596 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, primitive_color);
597 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_color);
598 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, primitive_color);
599 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
600 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 0)) {
601 diag_1 = 17;
602 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_color);
603 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, slice_points.at(1) + buffer, primitive_color);
604 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, primitive_color);
605 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
606 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 2)) {
607 diag_1 = 18;
608 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
609 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
610 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
611 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
612 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 1)) {
613 diag_1 = 19;
614 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
615 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
616 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
617 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
618 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 2)) {
619 diag_1 = 20;
620 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
621 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, slice_points.at(1) + buffer, primitive_color);
622 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
623 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_color);
624 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 3)) {
625 diag_1 = 21;
626 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(3) - buffer, slice_points.at(1) - buffer, primitive_color);
627 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
628 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
629 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_color);
630 }
631
632 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
633 if (this->context->getPrimitiveArea(t0) < minArea) {
634 this->context->deletePrimitive(t0);
635 } else {
636 resulting_UUIDs.push_back(t0);
637 }
638 if (this->context->getPrimitiveArea(t1) < minArea) {
639 this->context->deletePrimitive(t1);
640 } else {
641 resulting_UUIDs.push_back(t1);
642 }
643 if (this->context->getPrimitiveArea(t2) < minArea) {
644 this->context->deletePrimitive(t2);
645 } else {
646 resulting_UUIDs.push_back(t2);
647 }
648 if (this->context->getPrimitiveArea(t3) < minArea) {
649 this->context->deletePrimitive(t3);
650 } else {
651 resulting_UUIDs.push_back(t3);
652 }
653
654 } else if (initial_slice_points_size == 3) {
655 // split into three triangles instead of four since one vertex falls on the slicing face
656
657 if (slice_points_edge_ID.at(0) == 0 && vertex_index == 2) {
658 diag_1 = 22;
659 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
660 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, primitive_color);
661 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
662 } else if (slice_points_edge_ID.at(0) == 0 && vertex_index == 3) {
663 diag_1 = 23;
664 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
665 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, primitive_color);
666 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
667 } else if (slice_points_edge_ID.at(0) == 1 && vertex_index == 3) {
668 diag_1 = 24;
669 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
670 t1 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
671 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
672 } else if (slice_points_edge_ID.at(0) == 1 && vertex_index == 0) {
673 diag_1 = 25;
674 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
675 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, primitive_color);
676 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
677 } else if (slice_points_edge_ID.at(0) == 2 && vertex_index == 1) {
678 diag_1 = 26;
679 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
680 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, slice_points.at(1) + buffer, primitive_color);
681 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
682 } else if (slice_points_edge_ID.at(0) == 2 && vertex_index == 0) {
683 diag_1 = 27;
684 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, slice_points.at(1) + buffer, primitive_color);
685 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
686 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
687 } else if (slice_points_edge_ID.at(0) == 3 && vertex_index == 2) {
688 diag_1 = 28;
689 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
690 t1 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_color);
691 t2 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
692 } else if (slice_points_edge_ID.at(0) == 3 && vertex_index == 1) {
693 diag_1 = 29;
694 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, primitive_color);
695 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
696 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
697 }
698
699 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
700 if (this->context->getPrimitiveArea(t0) < minArea) {
701 this->context->deletePrimitive(t0);
702 } else {
703 resulting_UUIDs.push_back(t0);
704 }
705 if (this->context->getPrimitiveArea(t1) < minArea) {
706 this->context->deletePrimitive(t1);
707 } else {
708 resulting_UUIDs.push_back(t1);
709 }
710 if (this->context->getPrimitiveArea(t2) < minArea) {
711 this->context->deletePrimitive(t2);
712 } else {
713 resulting_UUIDs.push_back(t2);
714 }
715
716 } else if (initial_slice_points_size == 4) {
717 // split into two triangles instead of four since both vertices fall on the slicing face
718 if (vertex_index == 0 || vertex_index == 2) {
719 diag_1 = 30;
720 t0 = this->context->addTriangle(primitive_vertices.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_color);
721 t1 = this->context->addTriangle(primitive_vertices.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, primitive_color);
722
723 } else if (vertex_index == 1 || vertex_index == 3) {
724 diag_1 = 31;
725 t0 = this->context->addTriangle(primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, primitive_color);
726 t1 = this->context->addTriangle(primitive_vertices.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_color);
727 }
728
729 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
730 if (this->context->getPrimitiveArea(t0) < minArea) {
731 this->context->deletePrimitive(t0);
732 } else {
733 resulting_UUIDs.push_back(t0);
734 }
735 if (this->context->getPrimitiveArea(t1) < minArea) {
736 this->context->deletePrimitive(t1);
737 } else {
738 resulting_UUIDs.push_back(t1);
739 }
740 }
741 }
742
743 } else if (primitiveHasTexture) {
744
745 // get uv coordinates of the vertices
746 std::vector<helios::vec2> v_uv = this->context->getPrimitiveTextureUV(UUID);
747
748 // get uv coordinates of the intersection points
749 std::vector<helios::vec2> ip_uv;
750 ip_uv.resize(2);
751
752 if (primitive_vertices.size() == 3) {
753
754 // split into three triangles (usual case)
755 if (initial_slice_points_size == 2) {
756 for (uint i = 0; i < slice_points.size(); i++) {
757 // vectors to hold point coordinates and uv coordinates for the points on the current point's edge
758 helios::vec3 point_0;
759 helios::vec3 point_1;
760 helios::vec2 point_0uv;
761 helios::vec2 point_1uv;
762 helios::vec2 point_uv;
763
764 if (slice_points_edge_ID.at(i) == 0) {
765 point_0 = primitive_vertices.at(0);
766 point_1 = primitive_vertices.at(1);
767 point_0uv = v_uv.at(0);
768 point_1uv = v_uv.at(1);
769 } else if (slice_points_edge_ID.at(i) == 1) {
770 point_0 = primitive_vertices.at(1);
771 point_1 = primitive_vertices.at(2);
772 point_0uv = v_uv.at(1);
773 point_1uv = v_uv.at(2);
774 } else if (slice_points_edge_ID.at(i) == 2) {
775 point_0 = primitive_vertices.at(2);
776 point_1 = primitive_vertices.at(0);
777 point_0uv = v_uv.at(2);
778 point_1uv = v_uv.at(0);
779 }
780
781 ip_uv.at(i) = interpolate_texture_UV_to_slice_point(point_0, point_0uv, point_1, point_1uv, slice_points.at(i));
782
783 if (ip_uv.at(0).x < 0 || ip_uv.at(0).x > 1 || ip_uv.at(0).y < 0 || ip_uv.at(0).y > 1) {
784 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): texture UV coordinates for UUID " + std::to_string(UUID) + " are out of valid range [0,1].");
785 }
786 }
787
788 if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 1)) {
789 diag_1 = 101;
790 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(1), ip_uv.at(1));
791 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(2) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
792 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(0));
793 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 0)) {
794 diag_1 = 102;
795 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(1));
796 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
797 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(1), v_uv.at(2), v_uv.at(0));
798 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 2)) {
799 diag_1 = 103;
800 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
801 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
802 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
803 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 0)) {
804 diag_1 = 104;
805 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
806 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
807 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(1), v_uv.at(1), v_uv.at(2));
808 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 2)) {
809 diag_1 = 105;
810 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
811 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
812 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
813 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 1)) {
814 diag_1 = 106;
815 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
816 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
817 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(1), v_uv.at(0), v_uv.at(1));
818 }
819
820 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
821 if (this->context->getPrimitiveArea(t0) < minArea) {
822 this->context->deletePrimitive(t0);
823 } else {
824 resulting_UUIDs.push_back(t0);
825 }
826 if (this->context->getPrimitiveArea(t1) < minArea) {
827 this->context->deletePrimitive(t1);
828 } else {
829 resulting_UUIDs.push_back(t1);
830 }
831 if (this->context->getPrimitiveArea(t2) < minArea) {
832 this->context->deletePrimitive(t2);
833 } else {
834 resulting_UUIDs.push_back(t2);
835 }
836
837 // split into two triangles instead of three since a vertex falls on the slicing face
838 // the non-vertex slice point is slice_points.at(0) and the vertex slice point is slice_points.at(1)
839 } else if (initial_slice_points_size == 3) {
840
841 // std::cout << "initial_slice_points_size = " << initial_slice_points_size << std::endl;
842
843 // vectors to hold point coordinates and uv coordinates for the points on the current point's edge for interpolation
844 helios::vec3 point_0;
845 helios::vec3 point_1;
846 helios::vec2 point_0uv;
847 helios::vec2 point_1uv;
848 helios::vec2 point_uv;
849
850 if (slice_points_edge_ID.at(0) == 0) {
851 point_0 = primitive_vertices.at(0);
852 point_1 = primitive_vertices.at(1);
853 point_0uv = v_uv.at(0);
854 point_1uv = v_uv.at(1);
855 ip_uv.at(1) = v_uv.at(2); // this sets the uv coordinate for the vertex slice point
856
857 } else if (slice_points_edge_ID.at(0) == 1) {
858 point_0 = primitive_vertices.at(1);
859 point_1 = primitive_vertices.at(2);
860 point_0uv = v_uv.at(1);
861 point_1uv = v_uv.at(2);
862 ip_uv.at(1) = v_uv.at(0); // this sets the uv coordinate for the vertex slice point
863 } else if (slice_points_edge_ID.at(0) == 2) {
864 point_0 = primitive_vertices.at(2);
865 point_1 = primitive_vertices.at(0);
866 point_0uv = v_uv.at(2);
867 point_1uv = v_uv.at(0);
868 ip_uv.at(1) = v_uv.at(1); // this sets the uv coordinate for the vertex slice point
869 }
870
871 // UV for non-vertex slice point
872 ip_uv.at(0) = interpolate_texture_UV_to_slice_point(point_0, point_0uv, point_1, point_1uv, slice_points.at(0));
873
874 if (ip_uv.at(0).x < 0 || ip_uv.at(0).x > 1 || ip_uv.at(0).y < 0 || ip_uv.at(0).y > 1) {
875 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): texture UV coordinates for UUID " + std::to_string(UUID) + " are out of valid range [0,1].");
876 }
877
878 if (slice_points_edge_ID.at(0) == 0) {
879 diag_1 = 107;
880 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
881 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(1), ip_uv.at(1));
882 } else if (slice_points_edge_ID.at(0) == 1) {
883 diag_1 = 108;
884 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
885 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(1));
886 } else if (slice_points_edge_ID.at(0) == 2) {
887 diag_1 = 109;
888 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
889 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
890 }
891
892 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
893 if (this->context->getPrimitiveArea(t0) < minArea) {
894 this->context->deletePrimitive(t0);
895 } else {
896 resulting_UUIDs.push_back(t0);
897 }
898 if (this->context->getPrimitiveArea(t1) < minArea) {
899 this->context->deletePrimitive(t1);
900 } else {
901 resulting_UUIDs.push_back(t1);
902 }
903 }
904
905
906 } else if (primitive_vertices.size() == 4) {
907
908 // it seems patches that are not explicitly set up with texture UV coordinates just don't have them
909 // so set the default here
910 if (v_uv.size() == 0) {
911 std::vector<helios::vec2> uv{make_vec2(0, 0), make_vec2(1, 0), make_vec2(1, 1), make_vec2(0, 1)};
912 v_uv = uv;
913 }
914
915 // split into four triangles (usual case)
916 if (initial_slice_points_size == 2) {
917 // for each intersection point, choose the patch vertices on the corresponding edge
918 for (uint i = 0; i < 2; i++) {
919 helios::vec3 point_0;
920 helios::vec3 point_1;
921 helios::vec2 point_uv;
922 helios::vec2 point_0uv;
923 helios::vec2 point_1uv;
924
925 if (slice_points_edge_ID.at(i) == 0) {
926 point_0 = primitive_vertices.at(0);
927 point_1 = primitive_vertices.at(1);
928 point_0uv = v_uv.at(0);
929 point_1uv = v_uv.at(1);
930 } else if (slice_points_edge_ID.at(i) == 1) {
931 point_0 = primitive_vertices.at(1);
932 point_1 = primitive_vertices.at(2);
933 point_0uv = v_uv.at(1);
934 point_1uv = v_uv.at(2);
935 } else if (slice_points_edge_ID.at(i) == 2) {
936 point_0 = primitive_vertices.at(2);
937 point_1 = primitive_vertices.at(3);
938 point_0uv = v_uv.at(2);
939 point_1uv = v_uv.at(3);
940 } else if (slice_points_edge_ID.at(i) == 3) {
941 point_0 = primitive_vertices.at(3);
942 point_1 = primitive_vertices.at(0);
943 point_0uv = v_uv.at(3);
944 point_1uv = v_uv.at(0);
945 }
946
947 ip_uv.at(i) = interpolate_texture_UV_to_slice_point(point_0, point_0uv, point_1, point_1uv, slice_points.at(i));
948
949 if (ip_uv.at(i).x < 0 || ip_uv.at(i).x > 1 || ip_uv.at(i).y < 0 || ip_uv.at(i).y > 1) {
950 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): texture UV coordinates for UUID " + std::to_string(UUID) + " are out of valid range [0,1].");
951 }
952 }
953
954 // cases where intersection points are on opposite sides
955 if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 2)) {
956 diag_1 = 110;
957 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
958 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
959 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(1), v_uv.at(3), v_uv.at(0));
960 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
961 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 0)) {
962 diag_1 = 111;
963 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
964 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
965 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(0));
966 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(1), v_uv.at(1), v_uv.at(2));
967 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 3)) {
968 diag_1 = 112;
969 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(1));
970 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(3) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(3), ip_uv.at(1));
971 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(1), v_uv.at(0), v_uv.at(1));
972 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(3));
973 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 1)) {
974 diag_1 = 113;
975 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(1), ip_uv.at(1));
976 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(3));
977 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
978 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(1), v_uv.at(2), v_uv.at(3));
979 // cases where intersection points are on adjacent sides
980 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 3)) {
981 diag_1 = 114;
982 t0 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
983 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
984 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
985 t3 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(1), v_uv.at(2), v_uv.at(3));
986 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 0)) {
987 diag_1 = 115;
988 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
989 t1 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
990 t2 = this->context->addTriangle(slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(1), v_uv.at(1), v_uv.at(2));
991 t3 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(3));
992 } else if ((slice_points_edge_ID.at(0) == 0 && slice_points_edge_ID.at(1) == 1)) {
993 diag_1 = 116;
994 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(1), ip_uv.at(1));
995 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(3));
996 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, tex, ip_uv.at(1), v_uv.at(2), v_uv.at(3));
997 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(0));
998 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 0)) {
999 diag_1 = 117;
1000 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(1) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(1));
1001 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(3), ip_uv.at(1));
1002 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(3));
1003 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(1), v_uv.at(3), v_uv.at(0));
1004 } else if ((slice_points_edge_ID.at(0) == 1 && slice_points_edge_ID.at(1) == 2)) {
1005 diag_1 = 118;
1006 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(2), ip_uv.at(1));
1007 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(0));
1008 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(1), v_uv.at(03), v_uv.at(0));
1009 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
1010 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 1)) {
1011 diag_1 = 119;
1012 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(2));
1013 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), ip_uv.at(1));
1014 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(0));
1015 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(1), v_uv.at(0), v_uv.at(1));
1016 } else if ((slice_points_edge_ID.at(0) == 3 && slice_points_edge_ID.at(1) == 2)) {
1017 diag_1 = 120;
1018 t0 = this->context->addTriangle(slice_points.at(0) - buffer, slice_points.at(1) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(3));
1019 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, slice_points.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(1), ip_uv.at(1));
1020 t2 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
1021 t3 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, primitive_vertices.at(2) + buffer, tex, ip_uv.at(1), v_uv.at(1), v_uv.at(2));
1022 } else if ((slice_points_edge_ID.at(0) == 2 && slice_points_edge_ID.at(1) == 3)) {
1023 diag_1 = 121;
1024 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(3) - buffer, slice_points.at(1) - buffer, tex, ip_uv.at(0), v_uv.at(3), ip_uv.at(1));
1025 t1 = this->context->addTriangle(slice_points.at(0) + buffer, slice_points.at(1) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), ip_uv.at(1), v_uv.at(1));
1026 t2 = this->context->addTriangle(slice_points.at(1) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(1), v_uv.at(0), v_uv.at(1));
1027 t3 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(1) + buffer, primitive_vertices.at(2) + buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
1028 }
1029
1030 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
1031 if (this->context->getPrimitiveArea(t0) < minArea) {
1032 this->context->deletePrimitive(t0);
1033 } else {
1034 resulting_UUIDs.push_back(t0);
1035 }
1036 if (this->context->getPrimitiveArea(t1) < minArea) {
1037 this->context->deletePrimitive(t1);
1038 } else {
1039 resulting_UUIDs.push_back(t1);
1040 }
1041 if (this->context->getPrimitiveArea(t2) < minArea) {
1042 this->context->deletePrimitive(t2);
1043 } else {
1044 resulting_UUIDs.push_back(t2);
1045 }
1046 if (this->context->getPrimitiveArea(t3) < minArea) {
1047 this->context->deletePrimitive(t3);
1048 } else {
1049 resulting_UUIDs.push_back(t3);
1050 }
1051
1052
1053 } else if (initial_slice_points_size == 3) {
1054
1055 // for the first intersection point (index 0), choose the endpoints of the edge to interpolate UV between
1056 // for this case where the other intersection point is at a primitive vertex, that vertex UV will be used
1057 for (uint i = 0; i < 1; i++) {
1058 helios::vec3 point_0;
1059 helios::vec3 point_1;
1060 helios::vec2 point_uv;
1061 helios::vec2 point_0uv;
1062 helios::vec2 point_1uv;
1063
1064 if (slice_points_edge_ID.at(i) == 0) {
1065 point_0 = primitive_vertices.at(0);
1066 point_1 = primitive_vertices.at(1);
1067 point_0uv = v_uv.at(0);
1068 point_1uv = v_uv.at(1);
1069 } else if (slice_points_edge_ID.at(i) == 1) {
1070 point_0 = primitive_vertices.at(1);
1071 point_1 = primitive_vertices.at(2);
1072 point_0uv = v_uv.at(1);
1073 point_1uv = v_uv.at(2);
1074 } else if (slice_points_edge_ID.at(i) == 2) {
1075 point_0 = primitive_vertices.at(2);
1076 point_1 = primitive_vertices.at(3);
1077 point_0uv = v_uv.at(2);
1078 point_1uv = v_uv.at(3);
1079 } else if (slice_points_edge_ID.at(i) == 3) {
1080 point_0 = primitive_vertices.at(3);
1081 point_1 = primitive_vertices.at(0);
1082 point_0uv = v_uv.at(3);
1083 point_1uv = v_uv.at(0);
1084 }
1085
1086 // std::cout << "point_0 = " << point_0 << std::endl;
1087 // std::cout << "point_0uv = " << point_0uv << std::endl;
1088 // std::cout << "point_1 = " << point_1 << std::endl;
1089 // std::cout << "point_1uv = " << point_1uv << std::endl;
1090 // std::cout << "i = " << i << std::endl;
1091 // std::cout << "slice_points.at(i) = " << slice_points.at(i) << std::endl;
1092 // std::cout << "slice_points.size() = " << slice_points.size() << std::endl;
1093 // std::cout << "slice_points_edge_ID.at(i) = " << slice_points_edge_ID.at(i) << std::endl;
1094
1095 ip_uv.at(i) = interpolate_texture_UV_to_slice_point(point_0, point_0uv, point_1, point_1uv, slice_points.at(i));
1096
1097 if (ip_uv.at(i).x < 0 || ip_uv.at(i).x > 1 || ip_uv.at(i).y < 0 || ip_uv.at(i).y > 1) {
1098 helios_runtime_error("ERROR (CollisionDetection::slicePrimitive): texture UV coordinates for UUID " + std::to_string(UUID) + " are out of valid range [0,1].");
1099 }
1100
1101
1102 if (slice_points_edge_ID.at(0) == 0 && vertex_index == 2) {
1103 diag_1 = 122;
1104 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(0));
1105 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
1106 t2 = this->context->addTriangle(primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, v_uv.at(2), v_uv.at(3), v_uv.at(0));
1107 } else if (slice_points_edge_ID.at(0) == 0 && vertex_index == 3) {
1108 diag_1 = 123;
1109 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(0));
1110 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(3));
1111 t2 = this->context->addTriangle(primitive_vertices.at(3) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, v_uv.at(3), v_uv.at(1), v_uv.at(2));
1112 } else if (slice_points_edge_ID.at(0) == 1 && vertex_index == 3) {
1113 diag_1 = 124;
1114 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(1));
1115 t1 = this->context->addTriangle(primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, v_uv.at(3), v_uv.at(0), v_uv.at(1));
1116 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(3));
1117 } else if (slice_points_edge_ID.at(0) == 1 && vertex_index == 0) {
1118 diag_1 = 125;
1119 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
1120 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(0) - buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(0));
1121 t2 = this->context->addTriangle(primitive_vertices.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, v_uv.at(0), v_uv.at(2), v_uv.at(3));
1122 } else if (slice_points_edge_ID.at(0) == 2 && vertex_index == 1) {
1123 diag_1 = 126;
1124 t0 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(2));
1125 t1 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(1));
1126 t2 = this->context->addTriangle(primitive_vertices.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, v_uv.at(1), v_uv.at(3), v_uv.at(0));
1127 } else if (slice_points_edge_ID.at(0) == 2 && vertex_index == 0) {
1128 diag_1 = 127;
1129 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, ip_uv.at(0), v_uv.at(3), v_uv.at(0));
1130 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(0) - buffer, primitive_vertices.at(2) - buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(2));
1131 t2 = this->context->addTriangle(primitive_vertices.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, v_uv.at(0), v_uv.at(1), v_uv.at(2));
1132 } else if (slice_points_edge_ID.at(0) == 3 && vertex_index == 2) {
1133 diag_1 = 128;
1134 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(2) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(2));
1135 t1 = this->context->addTriangle(primitive_vertices.at(2) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, v_uv.at(2), v_uv.at(0), v_uv.at(1));
1136 t2 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(2), v_uv.at(3));
1137 } else if (slice_points_edge_ID.at(0) == 3 && vertex_index == 1) {
1138 diag_1 = 129;
1139 t0 = this->context->addTriangle(slice_points.at(0) + buffer, primitive_vertices.at(0) + buffer, primitive_vertices.at(1) + buffer, tex, ip_uv.at(0), v_uv.at(0), v_uv.at(1));
1140 t1 = this->context->addTriangle(slice_points.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(3) - buffer, tex, ip_uv.at(0), v_uv.at(1), v_uv.at(3));
1141 t2 = this->context->addTriangle(primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, v_uv.at(1), v_uv.at(2), v_uv.at(3));
1142 }
1143
1144 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
1145 if (this->context->getPrimitiveArea(t0) < minArea) {
1146 this->context->deletePrimitive(t0);
1147 } else {
1148 resulting_UUIDs.push_back(t0);
1149 }
1150 if (this->context->getPrimitiveArea(t1) < minArea) {
1151 this->context->deletePrimitive(t1);
1152 } else {
1153 resulting_UUIDs.push_back(t1);
1154 }
1155 if (this->context->getPrimitiveArea(t2) < minArea) {
1156 this->context->deletePrimitive(t2);
1157 } else {
1158 resulting_UUIDs.push_back(t2);
1159 }
1160 }
1161
1162 } else if (initial_slice_points_size == 4) {
1163
1164 if (vertex_index == 0 || vertex_index == 2) {
1165 diag_1 = 130;
1166 t0 = this->context->addTriangle(primitive_vertices.at(0) - buffer, primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, tex, v_uv.at(0), v_uv.at(1), v_uv.at(2));
1167 t1 = this->context->addTriangle(primitive_vertices.at(0) + buffer, primitive_vertices.at(2) + buffer, primitive_vertices.at(3) + buffer, tex, v_uv.at(0), v_uv.at(2), v_uv.at(3));
1168
1169 } else if (vertex_index == 1 || vertex_index == 3) {
1170 diag_1 = 131;
1171 t0 = this->context->addTriangle(primitive_vertices.at(1) - buffer, primitive_vertices.at(2) - buffer, primitive_vertices.at(3) - buffer, tex, v_uv.at(1), v_uv.at(2), v_uv.at(3));
1172 t1 = this->context->addTriangle(primitive_vertices.at(1) + buffer, primitive_vertices.at(3) + buffer, primitive_vertices.at(0) + buffer, tex, v_uv.at(1), v_uv.at(3), v_uv.at(0));
1173 }
1174
1175 // delete triangles with area of zero, otherwise add to resulting_UUIDs vector
1176 if (this->context->getPrimitiveArea(t0) < minArea) {
1177 this->context->deletePrimitive(t0);
1178 } else {
1179 resulting_UUIDs.push_back(t0);
1180 }
1181 if (this->context->getPrimitiveArea(t1) < minArea) {
1182 this->context->deletePrimitive(t1);
1183 } else {
1184 resulting_UUIDs.push_back(t1);
1185 }
1186 }
1187 }
1188 }
1189
1190 // print this out to find where a certain triangle is created
1191 // std::cout << "diag_1 = " << diag_1 << std::endl;
1192
1193 // copy over primitive data to the new triangles
1194 for (uint i = 0; i < resulting_UUIDs.size(); i++) {
1195 this->context->copyPrimitiveData(UUID, resulting_UUIDs.at(i));
1196 uint parentID = this->context->getPrimitiveParentObjectID(UUID);
1197 if (parentID > 0 && this->context->getObjectType(parentID) == helios::OBJECT_TYPE_TILE) {
1198 this->context->setPrimitiveParentObjectID(resulting_UUIDs.at(i), 0);
1199 } else {
1200 this->context->setPrimitiveParentObjectID(resulting_UUIDs.at(i), parentID);
1201 }
1202 if (this->context->isPrimitiveTextureColorOverridden(UUID)) {
1203 this->context->overridePrimitiveTextureColor(resulting_UUIDs.at(i));
1204 }
1205 }
1206
1207 // compare original and resulting primitive areas to make sure they approximately match
1208 float resulting_area = this->context->sumPrimitiveSurfaceArea(resulting_UUIDs);
1209 float pdiff_area = (resulting_area - original_area) / original_area * 100.0;
1210 float pdiff_area_abs = fabs(pdiff_area);
1211 if (pdiff_area_abs > 1) {
1212 warnings.addWarning("slice_area_mismatch", "Sum of slice areas does not equal area of original primitive (UUID = " + std::to_string(UUID) + ", original area = " + std::to_string(original_area) +
1213 ", resulting area = " + std::to_string(resulting_area) + ", percent difference = " + std::to_string(pdiff_area) + "%)");
1214 }
1215
1216 // compare original and resulting primitive normals to make sure they match
1217 absTol = 0.5;
1218 relTol = 0.4;
1219 for (uint aa = 0; aa < resulting_UUIDs.size(); aa++) {
1220 helios::vec3 this_normal = this->context->getPrimitiveNormal(resulting_UUIDs.at(aa));
1221 this_normal.normalize();
1222 if (!approxSame(primitive_normal.x, this_normal.x, absTol, relTol) || !approxSame(primitive_normal.y, this_normal.y, absTol, relTol) || !approxSame(primitive_normal.z, this_normal.z, absTol, relTol)) {
1223 warnings.addWarning("slice_normal_mismatch", "UUID " + std::to_string(resulting_UUIDs.at(aa)) + " normal (" + std::to_string(this_normal.x) + ", " + std::to_string(this_normal.y) + ", " + std::to_string(this_normal.z) +
1224 ") does not match original normal (" + std::to_string(primitive_normal.x) + ", " + std::to_string(primitive_normal.y) + ", " + std::to_string(primitive_normal.z) + ")");
1225 }
1226 }
1227
1228 // delete the original primitive
1229 this->context->deletePrimitive(UUID);
1230
1231 return resulting_UUIDs;
1232}
1233
1234std::vector<uint> CollisionDetection::slicePrimitivesUsingGrid(const std::vector<uint> &UUIDs, const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions) {
1235
1236 // Create warning aggregator
1238 warnings.setEnabled(this->printmessages);
1239
1240 // set up the grid
1241 std::vector<std::vector<helios::vec3>> grid_face_vertices;
1242 helios::vec3 grid_min = make_vec3(grid_center.x - grid_size.x * 0.5, grid_center.y - grid_size.y * 0.5, grid_center.z - grid_size.z * 0.5);
1243 helios::vec3 grid_max = make_vec3(grid_center.x + grid_size.x * 0.5, grid_center.y + grid_size.y * 0.5, grid_center.z + grid_size.z * 0.5);
1244 helios::vec3 grid_spacing = make_vec3(grid_size.x / grid_divisions.x, grid_size.y / grid_divisions.y, grid_size.z / grid_divisions.z);
1245
1246 // faces in the y-z plane (change x)
1247 for (uint k = 0; k < (grid_divisions.x + 1); k++) {
1248 std::vector<helios::vec3> this_face_vertices;
1249 this_face_vertices.push_back(make_vec3(grid_min.x + k * grid_spacing.x, grid_min.y, grid_min.z));
1250 this_face_vertices.push_back(make_vec3(grid_min.x + k * grid_spacing.x, grid_min.y, grid_max.z));
1251 this_face_vertices.push_back(make_vec3(grid_min.x + k * grid_spacing.x, grid_max.y, grid_min.z));
1252 this_face_vertices.push_back(make_vec3(grid_min.x + k * grid_spacing.x, grid_max.y, grid_max.z));
1253 grid_face_vertices.push_back(this_face_vertices);
1254 }
1255
1256 // faces in the x-z plane (change y)
1257 for (uint k = 0; k < (grid_divisions.y + 1); k++) {
1258 std::vector<helios::vec3> this_face_vertices;
1259 this_face_vertices.push_back(make_vec3(grid_min.x, grid_min.y + k * grid_spacing.y, grid_min.z));
1260 this_face_vertices.push_back(make_vec3(grid_min.x, grid_min.y + k * grid_spacing.y, grid_max.z));
1261 this_face_vertices.push_back(make_vec3(grid_max.x, grid_min.y + k * grid_spacing.y, grid_min.z));
1262 this_face_vertices.push_back(make_vec3(grid_max.x, grid_min.y + k * grid_spacing.y, grid_max.z));
1263 grid_face_vertices.push_back(this_face_vertices);
1264 }
1265
1266 // faces in the x-z plane (change y)
1267 for (uint k = 0; k < (grid_divisions.z + 1); k++) {
1268 std::vector<helios::vec3> this_face_vertices;
1269 this_face_vertices.push_back(make_vec3(grid_min.x, grid_min.y, grid_min.z + k * grid_spacing.z));
1270 this_face_vertices.push_back(make_vec3(grid_min.x, grid_max.y, grid_min.z + k * grid_spacing.z));
1271 this_face_vertices.push_back(make_vec3(grid_max.x, grid_min.y, grid_min.z + k * grid_spacing.z));
1272 this_face_vertices.push_back(make_vec3(grid_max.x, grid_max.y, grid_min.z + k * grid_spacing.z));
1273 grid_face_vertices.push_back(this_face_vertices);
1274 }
1275
1276 if (this->printmessages) {
1277 std::cout << UUIDs.size() << " input primitives" << std::endl;
1278 std::cout << grid_face_vertices.size() << " grid faces used for slicing" << std::endl;
1279 std::cout << grid_divisions.x * grid_divisions.y * grid_divisions.z << " total grid cells" << std::endl;
1280 }
1281
1282
1284 // do an initial classification of primitives into grid cells based on if all their vertices fall into a given voxel
1285
1286 this->grid_cells.clear();
1287 this->grid_cells.resize(grid_divisions.x);
1288 for (uint i = 0; i < grid_divisions.x; i++) {
1289 this->grid_cells[i].resize(grid_divisions.y);
1290 for (uint j = 0; j < grid_divisions.y; j++) {
1291 this->grid_cells[i][j].resize(grid_divisions.z);
1292 }
1293 }
1294
1295 // initially set all UUIDs as outside any voxel
1296 this->context->setPrimitiveData(UUIDs, "cell_ID", int(-1));
1297
1298 // vectors for UUIDs that do and do not need to be sliced
1299 std::vector<uint> UUIDs_to_slice;
1300 std::vector<uint> UUIDs_no_slice;
1301
1302 auto start = std::chrono::high_resolution_clock::now();
1303 for (uint p = 0; p < UUIDs.size(); p++) {
1304 bool flag = false;
1305 for (uint k = 0; k < (grid_divisions.z); k++) {
1306 for (uint j = 0; j < (grid_divisions.y); j++) {
1307 for (uint i = 0; i < (grid_divisions.x); i++) {
1308 helios::vec3 cell_min = make_vec3(grid_min.x + float(i) * grid_spacing.x, grid_min.y + float(j) * grid_spacing.y, grid_min.z + float(k) * grid_spacing.z);
1309 helios::vec3 cell_max = make_vec3(grid_min.x + float(i) * grid_spacing.x + grid_spacing.x, grid_min.y + float(j) * grid_spacing.y + grid_spacing.y, grid_min.z + float(k) * grid_spacing.z + grid_spacing.z);
1310 std::vector<helios::vec3> verts = this->context->getPrimitiveVertices(UUIDs.at(p));
1311
1312 uint v_in = 0;
1313 for (uint v = 0; v < verts.size(); v++) {
1314
1315 bool test2_x = (verts.at(v).x >= cell_min.x) && (verts.at(v).x <= cell_max.x);
1316 bool test2_y = (verts.at(v).y >= cell_min.y) && (verts.at(v).y <= cell_max.y);
1317 bool test2_z = (verts.at(v).z >= cell_min.z) && (verts.at(v).z <= cell_max.z);
1318
1319 if (test2_x && test2_y && test2_z) {
1320 v_in++;
1321 }
1322 }
1323
1324 if (v_in == verts.size()) {
1325 // the UUID doesn't need to be sliced since its vertices all are within a cell
1326 int cell_ID = i * grid_divisions.y * grid_divisions.z + j * grid_divisions.z + k;
1327 this->context->setPrimitiveData(UUIDs.at(p), "cell_ID", cell_ID);
1328 this->grid_cells[i][j][k].push_back(UUIDs.at(p));
1329 UUIDs_no_slice.push_back(UUIDs.at(p));
1330 flag = true;
1331 break;
1332 } else if (v_in != 0) {
1333 // some verticies in and some out: UUID needs to be sliced
1334 UUIDs_to_slice.push_back(UUIDs.at(p));
1335 flag = true;
1336 break;
1337 }
1338 }
1339 if (flag == true) {
1340 break;
1341 }
1342 }
1343 if (flag == true) {
1344 break;
1345 }
1346 }
1347
1348 // if all vertices fell outside of all grid cells, add it to be sliced just in case (corner cases)
1349 if (flag == false) {
1350 UUIDs_to_slice.push_back(UUIDs.at(p));
1351 }
1352 }
1353
1354 if (this->printmessages) {
1355
1356 auto stop = std::chrono::high_resolution_clock::now();
1357 auto duration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
1358 std::cout << duration.count() << " seconds to do initial grid cell classification" << std::endl;
1359 std::cout << UUIDs_no_slice.size() << " input primitives (" << float(UUIDs_no_slice.size()) / float(UUIDs.size()) * 100 << "%) not sliced" << std::endl;
1360 std::cout << UUIDs_to_slice.size() << " input primitives (" << float(UUIDs_to_slice.size()) / float(UUIDs.size()) * 100 << "%) being sliced" << std::endl;
1361 }
1362
1363
1365 // do the slicing
1366
1367 std::vector<uint> primitives_to_remove;
1368 std::vector<uint> primitives_to_add;
1369
1370 auto start2 = std::chrono::high_resolution_clock::now();
1371 // loop through each voxel face
1372 for (uint i = 0; i < grid_face_vertices.size(); i++) {
1373 for (uint j = 0; j < UUIDs_to_slice.size(); j++) {
1374 // slice
1375 std::vector<uint> resulting_UUIDs;
1376 resulting_UUIDs = slicePrimitive(UUIDs_to_slice.at(j), grid_face_vertices.at(i), warnings);
1377
1378 // update the UUIDs_to_slice vector so it doesn't include deleted primitives (the originals that were split)
1379 bool exists = this->context->doesPrimitiveExist(UUIDs_to_slice.at(j));
1380 if (!exists) {
1381 primitives_to_remove.push_back(j);
1382 primitives_to_add.insert(primitives_to_add.end(), resulting_UUIDs.begin(), resulting_UUIDs.end());
1383 }
1384 }
1385
1386 for (int k = primitives_to_remove.size() - 1; k >= 0; k--) {
1387 UUIDs_to_slice.erase(UUIDs_to_slice.begin() + primitives_to_remove.at(k));
1388 }
1389 primitives_to_remove.clear();
1390
1391 UUIDs_to_slice.insert(UUIDs_to_slice.end(), primitives_to_add.begin(), primitives_to_add.end());
1392 primitives_to_add.clear();
1393 }
1394
1395 if (this->printmessages) {
1396
1397 auto stop2 = std::chrono::high_resolution_clock::now();
1398 auto duration2 = std::chrono::duration_cast<std::chrono::seconds>(stop2 - start2);
1399 std::cout << duration2.count() << " seconds to do slicing" << std::endl;
1400 }
1401
1403 // now classify the sliced primitives into grid cells
1404 // save the cell_ID as primitive data for the triangle
1405 // save the primitive UUID to a vector of UUIDs that are in a given cell and save that
1406
1407 auto start3 = std::chrono::high_resolution_clock::now();
1408
1409 for (uint p = 0; p < UUIDs_to_slice.size(); p++) {
1410 // std::cout << "UUIDs_to_slice.at(p) = " << UUIDs_to_slice.at(p) << std::endl;
1411 bool flag = false;
1412
1413 for (uint k = 0; k < (grid_divisions.z); k++) {
1414 for (uint j = 0; j < (grid_divisions.y); j++) {
1415 for (uint i = 0; i < (grid_divisions.x); i++) {
1416
1417 helios::vec3 cell_min = make_vec3(grid_min.x + i * grid_spacing.x, grid_min.y + j * grid_spacing.y, grid_min.z + k * grid_spacing.z);
1418 helios::vec3 cell_max = make_vec3(grid_min.x + i * grid_spacing.x + grid_spacing.x, grid_min.y + j * grid_spacing.y + grid_spacing.y, grid_min.z + k * grid_spacing.z + grid_spacing.z);
1419
1420 std::vector<helios::vec3> verts = this->context->getPrimitiveVertices(UUIDs_to_slice.at(p));
1421 uint v_in = 0;
1422 for (uint v = 0; v < verts.size(); v++) {
1423
1424 float absTol = pow(10, -6);
1425 float relTol = pow(10, -20);
1426 bool test2_x = (verts.at(v).x > cell_min.x || approxSame(verts.at(v).x, cell_min.x, absTol, relTol)) && (verts.at(v).x < cell_max.x || approxSame(verts.at(v).x, cell_max.x, absTol, relTol));
1427 bool test2_y = (verts.at(v).y > cell_min.y || approxSame(verts.at(v).y, cell_min.y, absTol, relTol)) && (verts.at(v).y < cell_max.y || approxSame(verts.at(v).y, cell_max.y, absTol, relTol));
1428 bool test2_z = (verts.at(v).z > cell_min.z || approxSame(verts.at(v).z, cell_min.z, absTol, relTol)) && (verts.at(v).z < cell_max.z || approxSame(verts.at(v).z, cell_max.z, absTol, relTol));
1429
1430 if (test2_x && test2_y && test2_z) {
1431 v_in++;
1432 }
1433 }
1434
1435 if (v_in == verts.size()) {
1436 int cell_ID = i * grid_divisions.y * grid_divisions.z + j * grid_divisions.z + k;
1437 this->context->setPrimitiveData(UUIDs_to_slice.at(p), "cell_ID", cell_ID);
1438 this->grid_cells[i][j][k].push_back(UUIDs_to_slice.at(p));
1439 flag = true;
1440 break;
1441 }
1442 }
1443 if (flag == true) {
1444 break;
1445 }
1446 }
1447 if (flag == true) {
1448 break;
1449 }
1450 }
1451
1452 if (flag == false) {
1453 // Primitive doesn't fit in any cell - this is an error condition that should be reported
1454 if (this->printmessages) {
1455 std::cerr << "WARNING (CollisionDetection::slicePrimitivesUsingGrid): Primitive " << UUIDs_to_slice.at(p) << " does not fit in any grid cell after slicing" << std::endl;
1456 }
1457 }
1458 }
1459
1460 if (this->printmessages) {
1461 auto stop3 = std::chrono::high_resolution_clock::now();
1462 auto duration3 = std::chrono::duration_cast<std::chrono::seconds>(stop3 - start3);
1463 std::cout << duration3.count() << " seconds to do second classification" << std::endl;
1464 }
1466 // Join the unsliced and sliced primitive UUIDs back into a single vector
1467 std::vector<uint> UUIDs_out = UUIDs_no_slice;
1468 UUIDs_out.insert(UUIDs_out.end(), UUIDs_to_slice.begin(), UUIDs_to_slice.end());
1469
1470 if (this->printmessages) {
1471 std::cout << UUIDs_to_slice.size() << " primitives created from slicing" << std::endl;
1472 std::cout << UUIDs_out.size() << " total output primitives" << std::endl;
1473 }
1474
1475 // Report aggregated warnings
1476 warnings.report(std::cerr);
1477
1478 return UUIDs_out;
1479}
1480
1481// -------- VOXEL-PRIMITIVE INTERSECTION (OpenMP) --------
1482
1484 if (this->printmessages) {
1485 std::cout << "Calculating primitive-voxel intersections..." << std::flush;
1486 }
1487
1488 // Separate voxels from planar primitives
1489 std::vector<uint> voxel_uuids;
1490 std::vector<uint> primitive_uuids;
1491
1492 std::vector<uint> uuids_to_process = UUIDs.empty() ? this->context->getAllUUIDs() : UUIDs;
1493
1494 for (uint uuid: uuids_to_process) {
1495 if (this->context->getPrimitiveType(uuid) == PRIMITIVE_TYPE_VOXEL) {
1496 voxel_uuids.push_back(uuid);
1497 } else {
1498 primitive_uuids.push_back(uuid);
1499 }
1500 }
1501
1502 if (voxel_uuids.empty() || primitive_uuids.empty()) {
1503 if (this->printmessages) {
1504 std::cout << "done. WARNING: ";
1505 if (voxel_uuids.empty())
1506 std::cout << "no voxels found";
1507 if (primitive_uuids.empty())
1508 std::cout << "no planar primitives found";
1509 std::cout << std::endl;
1510 }
1511 return;
1512 }
1513
1514 // Get primitive centers (geometric centroid)
1515 std::vector<vec3> primitive_centers(primitive_uuids.size());
1516 for (size_t i = 0; i < primitive_uuids.size(); i++) {
1517 auto vertices = this->context->getPrimitiveVertices(primitive_uuids[i]);
1518 if (vertices.empty()) {
1519 helios_runtime_error("ERROR (CollisionDetection::calculatePrimitiveVoxelIntersection): Primitive " + std::to_string(primitive_uuids[i]) + " has no vertices");
1520 }
1521 vec3 centroid = make_vec3(0, 0, 0);
1522 for (const auto &v: vertices) {
1523 centroid = centroid + v;
1524 }
1525 primitive_centers[i] = centroid / static_cast<float>(vertices.size());
1526 }
1527
1528 // Get voxel data (center, size)
1529 // NOTE: Rotated voxels are NOT supported - voxels must be axis-aligned
1530 std::vector<vec3> voxel_centers(voxel_uuids.size());
1531 std::vector<vec3> voxel_sizes(voxel_uuids.size());
1532
1533 for (size_t i = 0; i < voxel_uuids.size(); i++) {
1534 voxel_centers[i] = this->context->getVoxelCenter(voxel_uuids[i]);
1535 voxel_sizes[i] = this->context->getVoxelSize(voxel_uuids[i]);
1536 }
1537
1538// Parallel processing with OpenMP (algorithm from insideVolume_vi CUDA kernel)
1539// WARNING: This implementation assumes axis-aligned voxels (rotation = 0)
1540#pragma omp parallel for schedule(dynamic)
1541 for (int p = 0; p < static_cast<int>(primitive_uuids.size()); p++) {
1542 vec3 prim_center = primitive_centers[p];
1543
1544 // Test against all voxels
1545 for (size_t v = 0; v < voxel_uuids.size(); v++) {
1546 vec3 voxel_center = voxel_centers[v];
1547 vec3 voxel_size = voxel_sizes[v];
1548
1549 // Note: VoxelIntersection CUDA code sets rotation=0 (not implemented)
1550 // Skipping rotation transformation for now
1551
1552 // Ray-box intersection test from origin (0,0,0) to primitive center
1553 vec3 origin = make_vec3(0, 0, 0);
1554 vec3 direction = prim_center - origin;
1555 float distance_to_center = direction.magnitude(); // Save distance BEFORE normalizing
1556 direction.normalize();
1557
1558 // AABB intersection (robust slab method with divide-by-zero handling)
1559 vec3 voxel_min = voxel_center - voxel_size * 0.5f;
1560 vec3 voxel_max = voxel_center + voxel_size * 0.5f;
1561
1562 float tx_min, tx_max, ty_min, ty_max, tz_min, tz_max;
1563 const float epsilon = 1e-8f;
1564
1565 // X-axis slab
1566 if (fabs(direction.x) < epsilon) {
1567 // Ray parallel to YZ plane
1568 if (origin.x < voxel_min.x || origin.x > voxel_max.x) {
1569 continue; // No intersection
1570 }
1571 tx_min = -std::numeric_limits<float>::infinity();
1572 tx_max = std::numeric_limits<float>::infinity();
1573 } else {
1574 tx_min = (voxel_min.x - origin.x) / direction.x;
1575 tx_max = (voxel_max.x - origin.x) / direction.x;
1576 if (tx_min > tx_max)
1577 std::swap(tx_min, tx_max);
1578 }
1579
1580 // Y-axis slab
1581 if (fabs(direction.y) < epsilon) {
1582 // Ray parallel to XZ plane
1583 if (origin.y < voxel_min.y || origin.y > voxel_max.y) {
1584 continue; // No intersection
1585 }
1586 ty_min = -std::numeric_limits<float>::infinity();
1587 ty_max = std::numeric_limits<float>::infinity();
1588 } else {
1589 ty_min = (voxel_min.y - origin.y) / direction.y;
1590 ty_max = (voxel_max.y - origin.y) / direction.y;
1591 if (ty_min > ty_max)
1592 std::swap(ty_min, ty_max);
1593 }
1594
1595 // Z-axis slab
1596 if (fabs(direction.z) < epsilon) {
1597 // Ray parallel to XY plane
1598 if (origin.z < voxel_min.z || origin.z > voxel_max.z) {
1599 continue; // No intersection
1600 }
1601 tz_min = -std::numeric_limits<float>::infinity();
1602 tz_max = std::numeric_limits<float>::infinity();
1603 } else {
1604 tz_min = (voxel_min.z - origin.z) / direction.z;
1605 tz_max = (voxel_max.z - origin.z) / direction.z;
1606 if (tz_min > tz_max)
1607 std::swap(tz_min, tz_max);
1608 }
1609
1610 float t_enter = std::max({tx_min, ty_min, tz_min});
1611 float t_exit = std::min({tx_max, ty_max, tz_max});
1612
1613 // Check if ray intersects box AND primitive center point is inside box
1614 if (t_enter < t_exit && t_exit > 1e-6f) {
1615 // Primitive center is inside voxel if its distance falls between entry and exit points
1616 if (distance_to_center >= t_enter && distance_to_center <= t_exit) {
1617#pragma omp critical
1618 {
1619 // Add primitive UUID to voxel's "inside_UUIDs" data (using modern template API)
1620 if (!this->context->doesPrimitiveDataExist(voxel_uuids[v], "inside_UUIDs")) {
1621 std::vector<uint> inside_list = {primitive_uuids[p]};
1622 this->context->setPrimitiveData(voxel_uuids[v], "inside_UUIDs", inside_list);
1623 } else {
1624 std::vector<uint> inside_list;
1625 this->context->getPrimitiveData(voxel_uuids[v], "inside_UUIDs", inside_list);
1626 inside_list.push_back(primitive_uuids[p]);
1627 this->context->setPrimitiveData(voxel_uuids[v], "inside_UUIDs", inside_list);
1628 }
1629 }
1630 break; // Primitive can only be in one voxel
1631 }
1632 }
1633 }
1634 }
1635
1636 if (this->printmessages) {
1637 std::cout << "done." << std::endl;
1638 }
1639}