33#include <NDEVR/Triangle.h>
34#include <NDEVR/Bounds.h>
35#include <NDEVR/LineSegment.h>
36#include <NDEVR/Vector.h>
37#include <NDEVR/Polygon.h>
38#include <NDEVR/Plane.h>
46 constexpr fltp08 intersection_epsilon = 0.0001;
63 template<u
int01 t_dims,
class t_type,
class t_vertex>
86 template<u
int01 t_dims,
class t_type,
class t_vertex>
90 for (
uint01 dim = 0; dim < t_dims; ++dim)
92 if (intersected_line.
vertex(A)[dim] < bounds[MIN][dim])
94 if (intersected_line.
vertex(B)[dim] < bounds[MIN][dim])
97 intersected_line.
vertex(A) = line.template pointAt<true>(bounds[MIN][dim], dim);
99 else if (intersected_line.
vertex(B)[dim] < bounds[MIN][dim])
101 intersected_line.
vertex(B) = line.template pointAt<true>(bounds[MIN][dim], dim);
103 if (intersected_line.
vertex(A)[dim] > bounds[MAX][dim])
105 if (intersected_line.
vertex(B)[dim] > bounds[MAX][dim])
108 intersected_line.
vertex(A) = line.template pointAt<true>(bounds[MAX][dim], dim);
110 else if (intersected_line.
vertex(B)[dim] > bounds[MAX][dim])
112 intersected_line.
vertex(B) = line.template pointAt<true>(bounds[MAX][dim], dim);
115 return intersected_line;
134 template<u
int01 t_dims,
class t_type,
class t_vertex>
137 const t_vertex tri_edge_ab(tri.
edge(A, B).ray());
138 const t_vertex tri_edge_ca(tri.
edge(A, C).ray());
139 const t_vertex line_ray(line.
ray().template normalized<t_type>());
140 const t_vertex cross_line_tri =
cross(line_ray, tri_edge_ca);
141 const t_type determinant =
dot(tri_edge_ab, cross_line_tri);
142 if (
abs(determinant) < epsilon)
143 return Constant<t_vertex>::Invalid;
146 const t_type u0 =
dot(t, cross_line_tri) / determinant;
148 return Constant<t_vertex>::Invalid;
149 const t_vertex q =
cross(t, tri_edge_ab);
150 const t_type v =
dot(line_ray, q) / determinant;
152 return Constant<t_vertex>::Invalid;
154 const t_type final_t =
dot(tri_edge_ca, q) / determinant;
155 if (final_t > -epsilon && final_t * final_t < line.
lengthSquared())
156 return final_t * line_ray + line.
vertex(A);
158 return Constant<t_vertex>::Invalid;
160 template<u
int01 t_dims,
class t_type,
class t_vertex>
161 constexpr LineSegment<t_dims, t_type> ClosestPoint(
const Triangle<t_dims, t_type, t_vertex>& tri,
const LineSegment<t_dims, t_type>& segment)
163 Vertex<t_dims, t_type> inter_point =
intersection(tri, segment);
165 return LineSegment<t_dims, t_type>(inter_point, inter_point);
167 LineSegment<t_dims, t_type> a = segment.template closestPoints<t_type>(tri.edge(B, A));
168 LineSegment<t_dims, t_type> b = segment.template closestPoints<t_type>(tri.edge(C, B));
169 LineSegment<t_dims, t_type> c = segment.template closestPoints<t_type>(tri.edge(A, C));
170 if (b.magnitudeSquared() > a.magnitudeSquared())
172 if (c.magnitudeSquared() > a.magnitudeSquared())
195 template<u
int01 t_dims,
class t_type,
class t_vertex>
199 const t_vertex normal_a = tri_a.template normal<true>();
200 const t_vertex normal_b = tri_b.template normal<true>();
201 if (normal_a == normal_b)
203 const t_type dot_1a =
dot(normal_b, tri_a.
vertex(A) - tri_b.
vertex(A));
204 const t_type dot_1b =
dot(normal_b, tri_a.
vertex(B) - tri_b.
vertex(A));
205 const t_type dot_1c =
dot(normal_b, tri_a.
vertex(C) - tri_b.
vertex(A));
206 if ((dot_1a > 0 && dot_1b > 0 && dot_1c > 0) || (dot_1a < 0 && dot_1b < 0 && dot_1c < 0))
209 if (dot_1a == 0 || dot_1b == 0 || dot_1c == 0)
213 const t_type dot_2a =
dot(normal_a, tri_b.
vertex(A) - tri_a.
vertex(A));
214 const t_type dot_2b =
dot(normal_a, tri_b.
vertex(B) - tri_a.
vertex(A));
215 const t_type dot_2c =
dot(normal_a, tri_b.
vertex(C) - tri_a.
vertex(A));
217 if ((dot_2a > 0 && dot_2b > 0 && dot_2c > 0) || (dot_2a < 0 && dot_2b < 0 && dot_2c < 0))
220 if (dot_2a == 0 || dot_2b == 0 || dot_2c == 0)
223 const t_vertex seg_a1(tri_a.
vertex(A) + (tri_a.
vertex(B) - tri_a.
vertex(A)) * (dot_1a / (dot_1a - dot_1b)));
224 const t_vertex seg_a2(tri_a.
vertex(A) + (tri_a.
vertex(C) - tri_a.
vertex(A)) * (dot_1a / (dot_1a - dot_1c)));
226 const t_vertex seg_b1(tri_b.
vertex(A) + (tri_b.
vertex(B) - tri_b.
vertex(A)) * (dot_2a / (dot_2a - dot_2b)));
227 const t_vertex seg_b2(tri_b.
vertex(A) + (tri_b.
vertex(C) - tri_b.
vertex(A)) * (dot_2a / (dot_2a - dot_2c)));
229 const t_vertex cross_normal =
cross(normal_a, normal_b).template normalized<t_type>();
231 const t_type tp13 =
dot(seg_a2 - seg_a1, cross_normal);
235 const t_type tq12 =
dot(seg_b1 - seg_a1, cross_normal);
236 const t_type tq13 =
dot(seg_b2 - seg_a1, cross_normal);
238 const t_type Iq1 =
getMin(tq12, tq13);
239 const t_type Iq2 =
getMax(tq12, tq13);
242 if (
abs(Ip1 - Iq1) * 2 < ((Ip2 - Ip1) + (Iq2 - Iq1)))
244 t_type n_b =
getMax(Ip1, Iq1);
245 t_type n_a =
getMin(Ip2, Iq2);
272 template<u
int01 t_dims,
class t_type,
class t_vertex>
276 const t_type signed_dist_a = plane.distanceTo(tri_a.
vertex(A));
277 const t_type signed_dist_b = plane.distanceTo(tri_a.
vertex(B));
278 const t_type signed_dist_c = plane.distanceTo(tri_a.
vertex(C));
282 if (signed_dist_a == 0.0)
284 if (signed_dist_b == 0.0)
286 if (signed_dist_c != 0.0)
293 else if (signed_dist_c == 0.0)
301 seg[seg_location++] = tri_a.
vertex(A);
304 if (signed_dist_b == 0.0)
306 if (signed_dist_c == 0.0)
312 seg[seg_location++] = tri_a.
vertex(B);
314 if (signed_dist_c == 0.0)
316 seg[seg_location++] = tri_a.
vertex(C);
318 if (signed_dist_a * signed_dist_b < 0)
320 t_type t = signed_dist_a / (signed_dist_a - signed_dist_b);
323 if (signed_dist_b * signed_dist_c < 0)
325 t_type t = signed_dist_b / (signed_dist_b - signed_dist_c);
328 if (signed_dist_c * signed_dist_a < 0)
330 t_type t = signed_dist_c / (signed_dist_c - signed_dist_a);
335 template<u
int01 t_dims,
class t_type,
class t_vertex>
336 static LineSegment<t_dims, t_type, t_vertex>
intersection(
const Plane<t_dims, t_type>& plane,
const Triangle<t_dims, t_type, t_vertex>& tri_a, t_type epsilon = 0)
344 template<u
int01 t_dims,
class t_type>
348 return IntersectionTypes::e_mixed;
349 return IntersectionTypes::e_outside;
352 template<u
int01 t_dims,
class t_type,
class t_vertex>
355 if (tri.contains(point))
356 return IntersectionTypes::e_mixed;
357 return IntersectionTypes::e_outside;
359 template<u
int01 t_dims,
class t_type,
class t_vertex>
362 if (bounds.contains(point))
363 return IntersectionTypes::e_mixed;
364 return IntersectionTypes::e_outside;
366 template<u
int01 t_dims,
class t_type,
class t_vertex>
369 if (rad.contains(point))
370 return IntersectionTypes::e_mixed;
371 return IntersectionTypes::e_outside;
374 template<
class t_type,
class t_vertex>
377 if (polygon.contains(point))
378 return IntersectionTypes::e_mixed;
379 return IntersectionTypes::e_outside;
383 template<u
int01 t_dims,
class t_type,
class t_vertex>
386 if(distanceSquared(line, vertex) < intersection_epsilon)
387 return IntersectionTypes::e_inside;
388 return IntersectionTypes::e_outside;
390 template<u
int01 t_dims,
class t_type,
class t_vertex>
393 if (distanceSquared(line, vertex) < intersection_epsilon)
394 return IntersectionTypes::e_inside;
395 return IntersectionTypes::e_outside;
398 template<u
int01 t_dims,
class t_type,
class t_vertex>
401 if (distanceSquared(left, right[A]) < intersection_epsilon)
403 if (distanceSquared(left, right[B]) < intersection_epsilon)
404 return IntersectionTypes::e_inside;
406 return IntersectionTypes::e_mixed;
408 if (distanceSquared(left, right) < intersection_epsilon)
409 return IntersectionTypes::e_mixed;
410 return IntersectionTypes::e_outside;
412 template<u
int01 t_dims,
class t_type,
class t_vertex>
416 t_vertex edge_ba = tri.vertex(B) - tri.vertex(A);
417 t_vertex edge_ca = tri.vertex(C) - tri.vertex(A);
418 t_vertex dir = line.ray().template normalized<t_type>();
419 t_vertex pvec(
cross(dir, edge_ca));
420 t_type det =
dot(edge_ba, pvec);
423 if (
abs(det) < epsilon)
424 return IntersectionTypes::e_outside;
427 t_vertex tvec = line.vertex(A) - tri.vertex(A);
428 t_type u =
dot(tvec, pvec) * invDet;
430 return IntersectionTypes::e_outside;
432 t_vertex qvec(
cross(tvec, edge_ba));
433 t_type v =
dot(dir, qvec) * invDet;
435 return IntersectionTypes::e_outside;
437 t_type t =
dot(edge_ca, qvec) * invDet;
438 if (t * t > line.lengthSquared())
439 return IntersectionTypes::e_outside;
440 return IntersectionTypes::e_mixed;
442 template<u
int01 t_dims,
class t_type,
class t_vertex>
445 return classify(bounds, line) == IntersectionTypes::e_outside ? IntersectionTypes::e_outside : IntersectionTypes::e_mixed;
447 template<u
int01 t_dims,
class t_type,
class t_vertex>
450 return polygon.template contains<t_type>(line.template as<2, t_type>());
454 template<u
int01 t_dims,
class t_type,
class t_vertex>
458 return IntersectionTypes::e_inside;
459 return IntersectionTypes::e_outside;
462 template<u
int01 t_dims,
class t_type,
class t_vertex>
466 return IntersectionTypes::e_mixed;
467 return IntersectionTypes::e_outside;
469 template<u
int01 t_dims,
class t_type,
class t_vertex>
472 const PlanePosition position_a = plane.planePosition(line.vertex(A));
473 const PlanePosition position_b = plane.planePosition(line.vertex(B));
474 if (position_a == position_b)
476 if (position_a == PlanePosition::e_on_plane)
477 return IntersectionTypes::e_inside;
479 return IntersectionTypes::e_outside;
481 return IntersectionTypes::e_mixed;
483 template<u
int01 t_dims,
class t_type,
class t_vertex>
486 const PlanePosition position_a = plane.planePosition(line.vertex(A));
487 const PlanePosition position_b = plane.planePosition(line.vertex(B));
488 if (position_a == position_b)
490 if (position_a == PlanePosition::e_on_plane)
491 return IntersectionTypes::e_mixed;
493 return IntersectionTypes::e_outside;
495 return IntersectionTypes::e_mixed;
500 template<u
int01 t_dims,
class t_type,
class t_vertex>
503 if (tri.contains(point))
504 return IntersectionTypes::e_inside;
505 return IntersectionTypes::e_outside;
507 template<u
int01 t_dims,
class t_type,
class t_vertex>
511 return IntersectionTypes::e_outside;
512 return IntersectionTypes::e_mixed;
515 template<u
int01 t_dims,
class t_type,
class t_vertex>
518 return polygon.template contains<t_type>(tri.template as<2, t_type>());
520 template<u
int01 t_dims,
class t_type,
class t_vertex>
523 const PlanePosition position_a = plane.planePosition(triangle.vertex(A));
524 const PlanePosition position_b = plane.planePosition(triangle.vertex(B));
525 const PlanePosition position_c = plane.planePosition(triangle.vertex(C));
526 if (position_a == position_b && position_a == position_c)
528 if (position_a == PlanePosition::e_on_plane)
529 return IntersectionTypes::e_mixed;
531 return IntersectionTypes::e_outside;
533 return IntersectionTypes::e_mixed;
535 template<u
int01 t_dims,
class t_type,
class t_vertex>
538 const PlanePosition position_a = plane.planePosition(triangle.vertex(A));
539 const PlanePosition position_b = plane.planePosition(triangle.vertex(B));
540 const PlanePosition position_c = plane.planePosition(triangle.vertex(C));
541 if (position_a == position_b && position_a == position_c)
543 if (position_a == PlanePosition::e_on_plane)
544 return IntersectionTypes::e_inside;
546 return IntersectionTypes::e_outside;
548 return IntersectionTypes::e_mixed;
553 template<u
int01 t_dims,
class t_type,
class t_vertex>
556 if (bounds.contains(vertex))
557 return IntersectionTypes::e_inside;
558 return IntersectionTypes::e_outside;
560 template<u
int01 t_dims,
class t_type,
class t_vertex>
563 if (bounds.contains(line))
565 return IntersectionTypes::e_inside;
568 for (
uint01 i = 0; i < t_dims; ++i)
570 if (bounds.doesIntersect(line.vertex(A)[i] - bounds[MIN][i], line.vertex(B)[i] - bounds[MIN][i], line.vertex(A), ray, i)
571 || bounds.doesIntersect(line.vertex(A)[i] - bounds[MAX][i], line.vertex(B)[i] - bounds[MAX][i], line.vertex(A), ray, i))
572 return IntersectionTypes::e_mixed;
574 return IntersectionTypes::e_outside;
576 template<u
int01 t_dims,
class t_type,
class t_vertex>
579 if (bounds.contains(tri))
580 return IntersectionTypes::e_inside;
583 const t_vertex min =
getMin(tri.vertex(A), tri.vertex(B), tri.vertex(C));
584 const t_vertex max =
getMax(tri.vertex(A), tri.vertex(B), tri.vertex(C));
585 for (
uint01 i = 0; i < t_dims; i++)
587 if (min[i] > bounds[MAX][i] || max[i] < bounds[MIN][i])
588 return IntersectionTypes::e_outside;
592 const t_vertex bounds_center(bounds.center());
594 t_vertex(tri.vertex(A) - bounds_center)
595 , t_vertex(tri.vertex(B) - bounds_center)
596 , t_vertex(tri.vertex(C) - bounds_center));
597 const t_vertex half_span(bounds.span() /
cast<t_type>(2));
598 const t_vertex edge[3] = { centered_tri.edge(A, B).ray(), centered_tri.edge(B, C).ray(), centered_tri.edge(C, A).ray() };
599 for (
uint01 edge_index = 0; edge_index < 3; ++edge_index)
601 const t_vertex cur_edge = edge[edge_index];
602 const t_vertex abs_edge =
abs(edge[edge_index]);
603 for (
uint01 i = 0; i < 3; ++i)
611 val_a = cur_edge[Z] * centered_tri.vertex(A)[Y] - cur_edge[Y] * centered_tri.vertex(A)[Z];
612 val_b = cur_edge[Z] * centered_tri.vertex(C)[Y] - cur_edge[Y] * centered_tri.vertex(C)[Z];
613 radius = abs_edge[Z] * half_span[Y] + abs_edge[Y] * half_span[Z];
616 val_a = -cur_edge[Z] * centered_tri.vertex(A)[X] + cur_edge[X] * centered_tri.vertex(A)[Z];
617 val_b = -cur_edge[Z] * centered_tri.vertex(C)[X] + cur_edge[X] * centered_tri.vertex(C)[Z];
618 radius = abs_edge[Z] * half_span[X] + abs_edge[X] * half_span[Z];
622 val_a = cur_edge[Y] * centered_tri.vertex(B)[X] - cur_edge[X] * centered_tri.vertex(B)[Y];
623 val_b = cur_edge[Y] * centered_tri.vertex(C)[X] - cur_edge[X] * centered_tri.vertex(C)[Y];
624 radius = abs_edge[Y] * half_span[X] + abs_edge[X] * half_span[Y];
629 if (val_a > radius || val_b < -radius)
630 return IntersectionTypes::e_outside;
634 if (val_b > radius || val_a < -radius)
635 return IntersectionTypes::e_outside;
639 const t_vertex normal =
cross(edge[0], edge[1]);
642 for (
uint01 i = 0; i < 3; i++)
644 t_type vertex_a_val = centered_tri.vertex(A)[i];
647 vertex_min[i] = -half_span[i] - vertex_a_val;
648 vertex_max[i] = half_span[i] - vertex_a_val;
652 vertex_min[i] = half_span[i] - vertex_a_val;
653 vertex_max[i] = -half_span[i] - vertex_a_val;
657 return IntersectionTypes::e_outside;
658 return IntersectionTypes::e_mixed;
660 template<u
int01 t_dims,
class t_type,
class t_vertex>
663 bool is_inside =
true;
664 for (
uint01 dim = 0; dim < t_dims; ++dim)
666 if (!(right[MIN][dim] >= left[MIN][dim]))
668 if (!(right[MAX][dim] >= left[MIN][dim]))
669 return IntersectionTypes::e_outside;
672 if (!(right[MAX][dim] <= left[MAX][dim]))
674 if (!(right[MIN][dim] <= left[MAX][dim]))
675 return IntersectionTypes::e_outside;
680 return IntersectionTypes::e_inside;
681 return IntersectionTypes::e_mixed;
683 template<u
int01 t_dims,
class t_type,
class t_vertex>
686 const t_vertex center = radial.center();
691 for (
uint01 dim = 0; dim < t_dims; ++dim)
693 if (center[dim] < bounds[MIN][dim])
694 sqr_dist += (bounds[MIN][dim] - center[dim]) * (bounds[MIN][dim] - center[dim]);
695 else if (center[dim] > bounds[MAX][dim])
696 sqr_dist += (center[dim] - bounds[MAX][dim]) * (center[dim] - bounds[MAX][dim]);
697 else if (center[dim] >= bounds[MIN] + radial.radius() && center[dim] <= bounds[MAX][dim] - radial.radius())
700 if (inside_dims == t_dims)
701 return IntersectionTypes::e_inside;
702 if (sqr_dist > radial.radius() * radial.radius())
703 return IntersectionTypes::e_outside;
704 return IntersectionTypes::e_mixed;
709 template<u
int01 t_dims,
class t_type,
class t_vertex>
712 return polygon.template contains<t_type>(bounds.template as<2, t_type>());
716 template<u
int01 t_dims,
class t_type,
class t_vertex>
719 t_vertex c = bounds.center();
720 t_vertex e = bounds[MAX] - c;
723 t_type r = (e *
abs(plane.normal)).sum();
726 t_type s =
dot(plane.normal, c) - plane.d;
730 return IntersectionTypes::e_mixed;
732 return IntersectionTypes::e_outside;
735 template<u
int01 t_dims,
class t_type,
class t_vertex>
738 return classify(bounds, plane);
742 template<u
int01 t_dims,
class t_type,
class t_vertex>
745 if (rad.contains(vector))
746 return IntersectionTypes::e_inside;
747 return IntersectionTypes::e_outside;
750 template<u
int01 t_dims,
class t_type,
class t_vertex>
755 for (
uint01 i = 0; i < t_dims; i++)
757 const t_type cir_center = radial.center()[i];
758 const t_type dist_max = (bounds[MAX][i] - cir_center) * (bounds[MAX][i] - cir_center);
759 const t_type dist_min = (bounds[MIN][i] - cir_center) * (bounds[MIN][i] - cir_center);
760 if (dist_max > dist_min)
763 if (cir_center < bounds[MIN][i])
769 if (cir_center > bounds[MAX][i])
773 const t_type rad_squared = radial.radius() * radial.radius();
774 if (max_tot < rad_squared)
775 return IntersectionTypes::e_inside;
776 if (min_tot < rad_squared)
777 return IntersectionTypes::e_mixed;
778 return IntersectionTypes::e_outside;
780 template<u
int01 t_dims,
class t_type,
class t_vertex>
783 t_vertex c = radial.center();
784 if (radial.radius() >= plane.distanceTo(c))
785 return IntersectionTypes::e_mixed;
787 return IntersectionTypes::e_outside;
789 template<u
int01 t_dims,
class t_type,
class t_vertex>
792 return classify(radial, plane);
795 template<
class t_type,
class t_vertex>
798 if (polygon.contains(vector))
799 return IntersectionTypes::e_inside;
800 return IntersectionTypes::e_outside;
804 template<u
int01 t_dims,
class t_type,
class t_vertex>
807 return polygon.template contains<t_type>(bounds.template as<2, t_type>());
811 template<u
int01 t_dims,
class t_type,
class t_vertex>
814 return polygon.template contains<t_type>(tri.template as<2, t_type>());
818 template<u
int01 t_dims,
class t_type,
class t_vertex>
821 return polygon.template contains<t_type>(line.template as<2, t_type>());
A specification of upper and lower bounds in N-dimensions.
Dummy class for including intersection functions.
constexpr t_type lengthSquared() const
constexpr const t_vertex & vertex(uint01 index) const
constexpr t_vertex ray() const
Logic for a given plane or N-dimensions.
A three-vertex polygon representing a triangle in N-dimensional space.
constexpr t_vertex & vertex(TriangleLocation triangle_node)
Vertices the given triangle node.
constexpr LineSegment< t_dims, t_type, t_vertex > edge(uint01 triangle_node_a, uint01 triangle_node_b) const
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
A point in N-dimensional space, used primarily for spatial location information.
The primary namespace for the NDEVR SDK.
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
constexpr t_type getMax(const t_type &left, const t_type &right)
Finds the max of the given arguments using the > operator The only requirement is that t_type have > ...
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
PlanePosition
The location of an object either below, above, or on a given N-dimensional plane.
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
constexpr Angle< t_angle_type > abs(const Angle< t_angle_type > &value)
Changes an input with a negative sign, to a positive sign.
static Bounds< t_dims, t_type, t_vertex > intersection(const Bounds< t_dims, t_type, t_vertex > &bounds_1, const Bounds< t_dims, t_type, t_vertex > &bounds_2)
Given two bounds, returns the intersection between the two of them.
double fltp08
Defines an alias representing an 8 byte floating-point number.
constexpr Vector< 1, t_type > cross(const Vector< 1, t_type > &, const Vector< 1, t_type > &)
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
IntersectionTypes
Used for classifying shape intersections.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...