NDEVR
API Documentation
Triangle.hpp
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: Triangle
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/BaseValues.h>
34#include <NDEVR/Vertex.h>
35#include <NDEVR/LineSegment.h>
36#include <NDEVR/Angle.h>
37#include <NDEVR/AngleDefinitions.h>
38
39namespace NDEVR
40{
47 {
48 outside_tri
49 , edge_ab
50 , edge_bc
51 , edge_ca
52 , vertex_a
53 , vertex_b
54 , vertex_c
55 , angle_a
56 , angle_b
57 , angle_c
58 , inside_tri
59 , mixed_location_tri
60 , tri_location_nan
61 };
62
66 {
67 public:
68 static constexpr TriangleLocation oppositeLocation(TriangleLocation location)
69 {
70 switch (location)
71 {
72 case vertex_a: return edge_bc;
73 case vertex_b: return edge_ca;
74 case vertex_c: return edge_ab;
75 case edge_bc: return vertex_a;
76 case edge_ca: return vertex_b;
77 case edge_ab: return vertex_c;
78 default:
79 lib_assert(false, "Segment does not have oposite value");
80 break;
81 }
82 return tri_location_nan;
83 }
84
93 {
94 switch (location)
95 {
96 case vertex_a: return vertex_b;
97 case vertex_b: return vertex_c;
98 case vertex_c: return vertex_a;
99 default:
100 lib_assert(false, "Not a valid vertex request");
101 return tri_location_nan;
102 }
103 }
104
113 {
114 switch (location)
115 {
116 case vertex_a: return vertex_c;
117 case vertex_b: return vertex_a;
118 case vertex_c: return vertex_b;
119 default:
120 lib_assert(false, "Not a valid vertex request");
121 return tri_location_nan;
122 }
123 }
124 };
125
140 template<uint01 t_dims, class t_type, class t_vertex = Vertex<t_dims, t_type>>
141 class Triangle : public Vector<3, t_vertex>, public TriangleBase
142 {
143 public:
144 constexpr Triangle()
145 {}
146 explicit constexpr Triangle(const t_type& a)
147 : Vector<3, t_vertex>(t_vertex(a), t_vertex(a), t_vertex(a))
148 {}
149 constexpr Triangle(const t_type& a, const t_type& b, const t_type& c)
150 : Vector<3, t_vertex>(t_vertex(a), t_vertex(b), t_vertex(c))
151 {}
152 explicit constexpr Triangle(const t_vertex& vector)
153 : Vector<3, t_vertex>(vector)
154 {}
155 constexpr Triangle(const t_vertex& a, const t_vertex& b, const t_vertex& c)
156 : Vector<3, t_vertex>(a, b, c)
157 {}
158
171
172 [[nodiscard]] constexpr t_vertex& vertex(TriangleLocation triangle_node)
173 {
174 switch (triangle_node)
175 {
176 case vertex_a: return vertex(A);
177 case vertex_b: return vertex(B);
178 case vertex_c: return vertex(C);
179 default: lib_assert(false, "Not a valid vertex request"); return vertex(A);
180 }
181 }
182
195
196 [[nodiscard]] constexpr const t_vertex& vertex(TriangleLocation triangle_node) const
197 {
198 switch (triangle_node)
199 {
200 case vertex_a: return vertex(A);
201 case vertex_b: return vertex(B);
202 case vertex_c: return vertex(C);
203 default: lib_assert(false, "Not a valid vertex request"); return vertex(A);
204 }
205 }
206
219
220 [[nodiscard]] constexpr t_vertex& vertex(uint01 triangle_node)
221 {
222 lib_assert(triangle_node <= 2, "Tried to access bad Triangle Node");
223 return (*this)[triangle_node];
224 }
225
238
239 [[nodiscard]] constexpr const t_vertex& vertex(uint01 triangle_node) const
240 {
241 lib_assert(triangle_node <= 2, "Tried to access bad Triangle Node");
242 return (*this)[triangle_node];
243 }
244
259
260 [[nodiscard]] constexpr LineSegment<t_dims, t_type, t_vertex> edge(uint01 triangle_node_a, uint01 triangle_node_b) const
261 {
262 lib_assert(triangle_node_a <= 2 && triangle_node_b <= 2, "Tried to access bad Triangle Node");
263 return LineSegment<t_dims, t_type, t_vertex>((*this)[triangle_node_a], (*this)[triangle_node_b]);
264 }
265
278
279 [[nodiscard]] constexpr LineSegment<t_dims, t_type, t_vertex> edge(TriangleLocation location) const
280 {
281 switch (location)
282 {
283 case edge_ab: return LineSegment<t_dims, t_type, t_vertex>(vertex(A), vertex(B));
284 case edge_bc: return LineSegment<t_dims, t_type, t_vertex>(vertex(B), vertex(C));
285 case edge_ca: return LineSegment<t_dims, t_type, t_vertex>(vertex(C), vertex(A));
286 default: lib_assert(false, "Not a valid line segment request"); return LineSegment<t_dims, t_type>();
287 }
288 }
289
302 template<class t_angle_type>
303 [[nodiscard]] constexpr Angle< t_angle_type> angle(uint01 triangle_node) const
304 {
305 lib_assert(triangle_node <= 2, "Tried to access bad Triangle Node");
306 const uint01 left = triangle_node > 0 ? triangle_node - 1 : 2;
307 const uint01 right = triangle_node < 2 ? triangle_node + 1 : 0;
308 return AngleDefinitions::Rotation<t_angle_type>(vertex(left), vertex(triangle_node), vertex(right));
309 }
310
311 [[nodiscard]] constexpr fltp08 tan(uint01 triangle_node) const
312 {
313 lib_assert(triangle_node <= 2, "Tried to access bad Triangle Node");
314 uint01 left = triangle_node > 0 ? triangle_node - 1 : 2;
315 uint01 right = triangle_node < 2 ? triangle_node + 1 : 0;
316
317 const Vector<t_dims, t_type> v_left(vertex(left) - vertex(triangle_node));
318 const Vector<t_dims, t_type> v_right(vertex(triangle_node) - vertex(right));
319 fltp08 x = dot(v_left, v_right);
320 fltp08 y = cast<fltp08>(sqrt(v_left.magnitudeSquared() * v_right.magnitudeSquared()));
321
322
323 return (y * sqrt(1.0 - ((x * x) / (y * y)))) / x;
324 }
325
338 template<class t_angle_type>
339 [[nodiscard]] constexpr Angle<t_angle_type> angle(TriangleLocation location) const
340 {
341 switch (location)
342 {
343 case angle_a: return angle<t_angle_type>(A);
344 case angle_b: return angle<t_angle_type>(B);
345 case angle_c: return angle<t_angle_type>(C);
346 default: lib_assert(false, "Not a valid vertex request"); return Angle<t_angle_type>(RADIANS, 0.0f);
347 }
348 }
349
350
360 template<class t_area_type>
361 [[nodiscard]] constexpr inline t_area_type area() const
362 {
364 }
365
375
376 [[nodiscard]] constexpr t_vertex centroid() const
377 {
378 return ((cast<t_type>(2) * edge(B, C).midpoint()) + vertex(A)) / cast<t_type>(3);
379 }
380
390
391 [[nodiscard]] constexpr t_vertex center() const
392 {
393 t_vertex avg = (vertex(A) + vertex(B) + vertex(C)) / cast<t_type>(3);
394 avg = clip(avg, getMin(vertex(A), vertex(B), vertex(C)), getMax(vertex(A), vertex(B), vertex(C)));
395 return avg;
396 }
397
398
408 template<uint01 t_new_dims, class t_new_type>
409 [[nodiscard]] constexpr Triangle<t_new_dims, t_new_type> as() const
410 {
411 return Triangle<t_new_dims, t_new_type>(vertex(A).template as<t_new_dims, t_new_type>(), vertex(B).template as<t_new_dims, t_new_type>(), vertex(C).template as<t_new_dims, t_new_type>());
412 }
413
414
424 template<bool is_normalized, class t_normal_type = t_type>
425 [[nodiscard]] constexpr Vector<t_dims, t_normal_type> normal() const
426 {
427 const Vector<t_dims, t_normal_type> edge1 = vertex(B).template as<t_dims, t_normal_type>() - vertex(A).template as<t_dims, t_normal_type>();
428 const Vector<t_dims, t_normal_type> edge2 = vertex(C).template as<t_dims, t_normal_type>() - vertex(A).template as<t_dims, t_normal_type>();
429 Vector<t_dims, t_normal_type> cross_product = cross(edge1, edge2);
430 if (is_normalized) cross_product = cross_product.template normalized<t_normal_type>();
431 return cross_product;
432 }
433
446
447 [[nodiscard]] constexpr inline bool contains(const Vector<t_dims - 1, t_type>& p) const
448 {
449 if((p[X] - vertex(B)[X]) * (vertex(A)[Y] - vertex(B)[Y]) - (vertex(A)[X] - vertex(B)[X]) * (p[Y] - vertex(B)[Y]) < cast<t_type>(0))
450 {
451 if ((p[X] - vertex(C)[X]) * (vertex(B)[Y] - vertex(C)[Y]) - (vertex(B)[X] - vertex(C)[X]) * (p[Y] - vertex(C)[Y]) >= cast<t_type>(0))
452 return false;
453 if ((p[X] - vertex(A)[X]) * (vertex(C)[Y] - vertex(A)[Y]) - (vertex(C)[X] - vertex(A)[X]) * (p[Y] - vertex(A)[Y]) >= cast<t_type>(0))
454 return false;
455 }
456 else
457 {
458 if ((p[X] - vertex(C)[X]) * (vertex(B)[Y] - vertex(C)[Y]) - (vertex(B)[X] - vertex(C)[X]) * (p[Y] - vertex(C)[Y]) < cast<t_type>(0))
459 return false;
460 if ((p[X] - vertex(A)[X]) * (vertex(C)[Y] - vertex(A)[Y]) - (vertex(C)[X] - vertex(A)[X]) * (p[Y] - vertex(A)[Y]) < cast<t_type>(0))
461 return false;
462 }
463 return true;
464 }
465
478
479 [[nodiscard]] constexpr bool contains(const t_vertex& vertex_point, t_type epsilon = t_type(0.0001)) const
480 {
481 //Check bounds first, as rest of code may take time
482 for(uint01 dim = 0; dim < t_dims; dim++)
483 if( getMax(vertex(A)[dim], vertex(B)[dim], vertex(C)[dim]) < vertex_point[dim]
484 || getMin(vertex(A)[dim], vertex(B)[dim], vertex(C)[dim]) > vertex_point[dim])
485 return false;
486 // Compute vectors
487 const t_vertex dca = vertex(C) - vertex(A);
488 const t_vertex dba = vertex(B) - vertex(A);
489 const t_vertex dbp = vertex_point - vertex(A);
490
491 // Compute dot products
492 t_type dotca = dot(dca, dca);
493 t_type dotcaba = dot(dca, dba);
494 t_type dotcabp = dot(dca, dbp);
495 t_type dotba = dot(dba, dba);
496 t_type dotbabp = dot(dba, dbp);
497
498 // Compute barycentric coordinates
499 t_type invDenom = (dotca * dotba - dotcaba * dotcaba);
500 t_type u = ((dotba * dotcabp) - (dotcaba * dotbabp)) / invDenom;
501 t_type v = ((dotca * dotbabp) - (dotcaba * dotcabp)) / invDenom;
502
503 // Check if point is in triangle
504 if ((u >= 0) && (v >= 0) && (u + v < 1))
505 {
506 return true;
507 }
508 else
509 {
510 for (uint01 location = edge_ab; location <= edge_ca; location++)
511 if (distanceSquared(edge(cast<TriangleLocation>(location)), vertex_point) <= epsilon)
512 return true;
513 }
514 return false;
515 }
516
532
533 [[nodiscard]] constexpr TriangleLocation sharesObject(TriangleLocation object_to_check, const Triangle<t_dims, t_type, t_vertex>& tri, t_type epsilon = 0) const
534 {
535 switch (object_to_check)
536 {
537 case edge_ab:
538 case edge_bc:
539 case edge_ca:
540 {
541 const LineSegment<t_dims, t_type> edge_a = edge(object_to_check);
542 for (uint01 i = edge_ab; i <= edge_ca; i++)
543 {
545 if (equals(edge_a, edge_b, epsilon))
546 return cast<TriangleLocation>(i);
547 }
548 return tri_location_nan;
549 }
550 case vertex_a:
551 case vertex_b:
552 case vertex_c:
553 {
554 const t_vertex vertex_1 = vertex(object_to_check);
555 for (uint01 i = vertex_a; i <= vertex_c; i++)
556 {
557 t_vertex vertex_2 = tri.vertex(cast<TriangleLocation>(i));
558 if (equals(vertex_1, vertex_2, epsilon))
559 return cast<TriangleLocation>(i);
560 }
561 return tri_location_nan;
562 }
563 case angle_a:
564 case angle_b:
565 case angle_c:
566 return tri_location_nan;
567 case inside_tri:
568 case outside_tri:
569 {
570 const t_vertex vertex_a = vertex(object_to_check);
571 for (uint01 i = 0; i <= 2; i++)
572 {
573 t_vertex vertex_b = tri.vertex(i);
574 if (equals(vertex_a, vertex_b, epsilon))
575 return cast<TriangleLocation>(i);
576 }
577 return tri_location_nan;
578 }
579 default:
580 return tri_location_nan;
581 }
582 }
583
598 [[nodiscard]] constexpr uint01 vertexIndex(const t_vertex& p) const
599 {
600 for (uint01 i = A; i <= C; ++i)
601 if (vertex(i) == p)
602 return i;
603 return Constant<uint01>::Invalid;
604 }
605 [[nodiscard]] constexpr TriangleLocation getIdentityOf(const t_vertex& p) const
606 {
607 for (uint01 i = A; i <= C; ++i)
608 if (vertex(i) == p)
609 return cast<TriangleLocation>(vertex_a + i);
610 return tri_location_nan;
611 }
612 [[nodiscard]] constexpr TriangleLocation getIdentityOf(const t_vertex& p, t_type epsilon) const
613 {
614 lib_assert(IsValid(p), "Cannot get triangle identity of Invalid type");
615 for (uint01 i = A; i <= C; ++i)
616 if (equals(vertex(i), p, epsilon))
617 return cast<TriangleLocation>(vertex_a + i);
618 return tri_location_nan;
619 }
620 [[nodiscard]] constexpr TriangleLocation getIdentityOf(const LineSegment<t_dims, t_type, t_vertex>& line, t_type epsilon) const
621 {
622 switch (getIdentityOf(line[A], epsilon))
623 {
624 case vertex_a:
625 switch (getIdentityOf(line[B], epsilon))
626 {
627 case vertex_a: return vertex_a;
628 case vertex_b: return edge_ab;
629 case vertex_c: return edge_ca;
630 default: return tri_location_nan;
631 }
632 case vertex_b:
633 switch (getIdentityOf(line[B], epsilon))
634 {
635 case vertex_a: return edge_ab;
636 case vertex_b: return vertex_b;
637 case vertex_c: return edge_bc;
638 default: return tri_location_nan;
639 }
640 case vertex_c:
641 switch (getIdentityOf(line[B], epsilon))
642 {
643 case vertex_a: return edge_ca;
644 case vertex_b: return edge_bc;
645 case vertex_c: return vertex_c;
646 default: return tri_location_nan;
647 }
648 default: return tri_location_nan;
649 }
650 }
651 [[nodiscard]] constexpr TriangleLocation getIdentityOf(const LineSegment<t_dims, t_type, t_vertex>& line) const
652 {
653 switch (getIdentityOf(line[A]))
654 {
655 case vertex_a:
656 switch (getIdentityOf(line[B]))
657 {
658 case vertex_a: return vertex_a;
659 case vertex_b: return edge_ab;
660 case vertex_c: return edge_ca;
661 default: return tri_location_nan;
662 }
663 case vertex_b:
664 switch (getIdentityOf(line[B]))
665 {
666 case vertex_a: return edge_ab;
667 case vertex_b: return vertex_b;
668 case vertex_c: return edge_bc;
669 default: return tri_location_nan;
670 }
671 case vertex_c:
672 switch (getIdentityOf(line[B]))
673 {
674 case vertex_a: return edge_ca;
675 case vertex_b: return edge_bc;
676 case vertex_c: return vertex_c;
677 default: return tri_location_nan;
678 }
679 default: return tri_location_nan;
680 }
681 }
682 [[nodiscard]] constexpr TriangleLocation getLocation(const t_vertex& p, t_type epsilon = cast<t_type>(0)) const
683 {
684 lib_assert(IsValid(p), "Cannot get triangle location of Invalid type");
685 for (uint01 i = A; i <= C; ++i)
686 if (equals(vertex(i), p, epsilon))
687 return cast<TriangleLocation>(i);
688 for(uint01 location = edge_ab; location <= edge_ca; location++)
689 if(distanceSquared(edge(cast<TriangleLocation>(location)), p) <= epsilon)
690 return cast<TriangleLocation>(location);
691
692 const t_vertex normal_abp = Triangle(vertex(A), vertex(B), p).normal<true>();
693 const t_vertex normal_bcp = Triangle(vertex(B), vertex(C), p).normal<true>();
694
695 const t_type dot_1 = dot(normal_abp, normal_bcp);
696 if(dot_1 >= epsilon + 1 || dot_1 <= -epsilon + 1)
697 return outside_tri;
698
699 const t_vertex normal_cap = Triangle(vertex(C), vertex(A), p).normal<true>();
700 const t_type dot_2 = dot(normal_bcp, normal_cap);
701 if((dot_2 >= epsilon + 1 && dot_2 <= -epsilon + 1))
702 return outside_tri;
703 return inside_tri;
704 }
705
706 [[nodiscard]] constexpr TriangleLocation getLocation(const LineSegment<t_dims, t_type, t_vertex>& line, t_type epsilon = cast<t_type>(0)) const
707 {
708 switch (getLocation(line[A], epsilon))
709 {
710 case edge_ab:
711 switch (getLocation(line[B], epsilon))
712 {
713 case vertex_a:
714 case vertex_b:
715 case edge_ab: return edge_ab;
716 case vertex_c:
717 case edge_ca:
718 case edge_bc:
719 case inside_tri: return inside_tri;
720 default: return mixed_location_tri;
721 }
722 case edge_bc:
723 switch (getLocation(line[B], epsilon))
724 {
725 case vertex_b:
726 case vertex_c:
727 case edge_bc: return edge_bc;
728 case vertex_a:
729 case edge_ca:
730 case edge_ab:
731 case inside_tri: return inside_tri;
732 default: return mixed_location_tri;
733 }
734 case edge_ca:
735 switch (getLocation(line[B], epsilon))
736 {
737 case vertex_c:
738 case vertex_a:
739 case edge_ca: return edge_ca;
740 case vertex_b:
741 case edge_ab:
742 case edge_bc:
743 case inside_tri: return inside_tri;
744 default: return mixed_location_tri;
745 }
746 case vertex_a:
747 switch (getLocation(line[B], epsilon))
748 {
749 case vertex_c: return edge_ca;
750 case vertex_b: return edge_ab;
751 case vertex_a: return vertex_a;
752 case edge_ca: return edge_ca;
753 case edge_ab: return edge_ab;
754 case edge_bc:
755 case inside_tri: return inside_tri;
756 default: return mixed_location_tri;
757 }
758 case vertex_b:
759 switch (getLocation(line[B], epsilon))
760 {
761 case vertex_b: return vertex_b;
762 case vertex_c: return edge_bc;
763 case vertex_a: return edge_ab;
764 case edge_bc: return edge_bc;
765 case edge_ab: return edge_ab;
766 case edge_ca:
767 case inside_tri: return inside_tri;
768 default: return mixed_location_tri;
769 }
770 case vertex_c:
771 switch (getLocation(line[B], epsilon))
772 {
773 case vertex_c: return vertex_c;
774 case vertex_b: return edge_bc;
775 case vertex_a: return edge_ca;
776 case edge_bc: return edge_bc;
777 case edge_ca: return edge_ca;
778 case edge_ab:
779 case inside_tri: return inside_tri;
780 default: return mixed_location_tri;
781 }
782 case inside_tri:
783 if (getLocation(line[B], epsilon) == outside_tri)
784 return mixed_location_tri;
785 else
786 return inside_tri;
787 case outside_tri:
788 if (getLocation(line[B], epsilon) == outside_tri)
789 return outside_tri;
790 else
791 return mixed_location_tri;
792 default:
793 lib_assert(false, "Should never arrive here in triangle identity line");
794 }
795 lib_assert(false, "Should never arrive here in triangle identity line");
796 return tri_location_nan;
797 }
798
806
807 constexpr void invert()
808 {
809 std::swap(vertex(C), vertex(B));
810 }
811
812
813
821 constexpr const t_vertex& nextVertexCCW(const t_vertex& point) const
822 {
823 return vertex(NextVertexCCW(getIdentityOf(point)));
824 }
825
833 constexpr const t_vertex& nextVertexCW(const t_vertex& point) const
834 {
835 return vertex(NextVertexCW(getIdentityOf(point)));
836 }
837 bool hasVertex(const t_vertex& point) const
838 {
839 return point == vertex(A) || point == vertex(B) || point == vertex(C);
840 }
841 };
842
843
844
845
860 template<uint01 t_dims, class t_type, class t_vertex>
861 constexpr Vector<t_dims, t_type> ClosestPoint(const Triangle<t_dims, t_type, t_vertex>& tri, const t_vertex& point)
862 {
863 const t_vertex edge0 = tri.edge(B, A).ray();
864 const t_vertex edge1 = tri.edge(C, A).ray();
865
866 const t_type a = dot(edge0, edge0);
867 const t_type b = dot(edge0, edge1);
868 const t_type c = dot(edge1, edge1);
869
870 const t_type det = a * c - b * b;
871
872 return ClosestPoint(tri, point, edge0, edge1, a, b, c, det);
873 }
874 template<uint01 t_dims, class t_type, class t_vertex>
875 constexpr Vector<t_dims, t_type> ClosestPoint(const Triangle<t_dims, t_type, t_vertex>& tri, const t_vertex& point, const t_vertex& edge0, const Vector<t_dims, t_type>& edge1, t_type a, t_type b, t_type c, t_type det)
876 {
877 const t_vertex v0(tri.vertex(A) - point);
878 const t_type d = dot(edge0, v0);
879 const t_type e = dot(edge1, v0);
880
881 t_type s = b * e - c * d;
882 t_type t = b * d - a * e;
883
884 if (s + t < det)
885 {
886 if (s < cast<t_type>(0))
887 {
888 if (t < cast<t_type>(0))
889 {
890 if (d < cast<t_type>(0))
891 {
892 s = clip(-d / a, cast<t_type>(0), cast<t_type>(1));
893 t = cast<t_type>(0);
894 }
895 else
896 {
897 s = cast<t_type>(0);
898 t = clip(-e / c, cast<t_type>(0), cast<t_type>(1));
899 }
900 }
901 else
902 {
903 s = cast<t_type>(0);
904 t = clip(-e / c, cast<t_type>(0), cast<t_type>(1));
905 }
906 }
907 else if (t < cast<t_type>(0))
908 {
909 s = clip(-d / a, cast<t_type>(0), cast<t_type>(1));
910 t = cast<t_type>(0);
911 }
912 else
913 {
914 t_type invDet = cast<t_type>(1) / det;
915 s *= invDet;
916 t *= invDet;
917 }
918 }
919 else
920 {
921 if (s < cast<t_type>(0))
922 {
923 t_type tmp0 = b + d;
924 t_type tmp1 = c + e;
925 if (tmp1 > tmp0)
926 {
927 t_type numer = tmp1 - tmp0;
928 t_type denom = a - 2 * b + c;
929 s = clip(numer / denom, cast<t_type>(0), cast<t_type>(1));
930 t = 1 - s;
931 }
932 else
933 {
934 t = clip(-e / c, cast<t_type>(0), cast<t_type>(1));
935 s = cast<t_type>(0);
936 }
937 }
938 else if (t < cast<t_type>(0))
939 {
940 if (a + d > b + e)
941 {
942 t_type numer = c + e - b - d;
943 t_type denom = a - 2 * b + c;
944 s = clip(numer / denom, cast<t_type>(0), cast<t_type>(1));
945 t = 1 - s;
946 }
947 else
948 {
949 s = clip(-e / c, cast<t_type>(0), cast<t_type>(1));
950 t = cast<t_type>(0);
951 }
952 }
953 else
954 {
955 t_type numer = c + e - b - d;
956 t_type denom = a - 2 * b + c;
957 s = clip(numer / denom, cast<t_type>(0), cast<t_type>(1));
958 t = cast<t_type>(1) - s;
959 }
960 }
961
962 return tri.vertex(A) + s * edge0 + t * edge1;
963 }
964
980 template<bool t_has_winding, uint01 t_dims, class t_type, class t_vertex>
981 constexpr bool Equals(const Triangle<t_dims, t_type, t_vertex>& tri_a, const Triangle<t_dims, t_type, t_vertex>& tri_b, t_type epsilon = 0)
982 {
983 uint01 dif = 0;
984 for (uint01 n = A; n <= C; ++n)
985 {
986 if(equals(tri_a.vertex(A), tri_b.vertex(n), epsilon))
987 break;
988 dif++;
989 }
990 if (tri_a.vertex(B) == tri_b.vertex((B + dif) % 3))
991 {
992 if (tri_a.vertex(C) == tri_b.vertex((C + dif) % 3))
993 return true;
994 }
995 else if(!t_has_winding && tri_a.vertex(B) == tri_b.vertex((C + dif) % 3))
996 {
997 if (tri_a.vertex(C) == tri_b.vertex((A + dif) % 3))
998 return true;
999 }
1000 return false;
1001 }
1002
1003
1004
1005
1006 template<uint01 t_dims, class t_type, class t_vector>
1007 struct Constant<Triangle<t_dims, t_type, t_vector>>
1008 {
1009 constexpr const static Triangle<t_dims, t_type, t_vector> Invalid{ Constant<t_vector>::Invalid, Constant<t_vector>::Invalid, Constant<t_vector>::Invalid };
1010 constexpr const static Triangle<t_dims, t_type, t_vector> Min{ Constant<t_vector>::Min, Constant<t_vector>::Min, Constant<t_vector>::Min };
1011 constexpr const static Triangle<t_dims, t_type, t_vector> Max{ Constant<t_vector>::Max, Constant<t_vector>::Max, Constant<t_vector>::Max };
1012 };
1013
1014 template<uint01 t_dims, class t_type>
1015 static constexpr bool IsInvalid(const Triangle<t_dims, t_type>& value)
1016 {
1017 for (uint01 dim = 0; dim < t_dims; ++dim)
1018 {
1019 if (IsInvalid(value[dim]))
1020 return true;
1021 }
1022 return false;
1023 }
1024 template<uint01 t_dims, class t_type>
1025 static constexpr bool IsValid(const Triangle<t_dims, t_type>& value)
1026 {
1027 for (uint01 dim = 0; dim < t_dims; ++dim)
1028 {
1029 if (IsInvalid(value[dim]))
1030 return false;
1031 }
1032 return true;
1033 }
1034};
static Angle< t_angle_type > Rotation(const Vector< t_dims, t_type > &left, const Vector< t_dims, t_type > &middle, const Vector< t_dims, t_type > &right)
Gets a rotation.
Stores an angle in an optimized internal format with support for efficient trigonometric operations.
Definition Angle.h:83
Class: LineSegment.
Definition Line.hpp:52
Base class for N-dimensional triangles.
Definition Triangle.hpp:66
static constexpr TriangleLocation NextVertexCCW(TriangleLocation location)
Returns the point location counter-clockwise to given point location.
Definition Triangle.hpp:92
static constexpr TriangleLocation NextVertexCW(TriangleLocation location)
Returns the point location clockwise to given point location.
Definition Triangle.hpp:112
A three-vertex polygon representing a triangle in N-dimensional space.
Definition Triangle.hpp:142
constexpr const t_vertex & nextVertexCCW(const t_vertex &point) const
Definition Triangle.hpp:821
constexpr t_vertex center() const
Definition Triangle.hpp:391
constexpr const t_vertex & nextVertexCW(const t_vertex &point) const
Definition Triangle.hpp:833
constexpr const t_vertex & vertex(TriangleLocation triangle_node) const
Vertices the given triangle node.
Definition Triangle.hpp:196
constexpr t_vertex & vertex(uint01 triangle_node)
Definition Triangle.hpp:220
constexpr t_vertex & vertex(TriangleLocation triangle_node)
Vertices the given triangle node.
Definition Triangle.hpp:172
constexpr bool contains(const Vector< t_dims - 1, t_type > &p) const
Definition Triangle.hpp:447
constexpr Triangle< t_new_dims, t_new_type > as() const
Definition Triangle.hpp:409
constexpr uint01 vertexIndex(const t_vertex &p) const
Definition Triangle.hpp:598
constexpr Angle< t_angle_type > angle(uint01 triangle_node) const
Definition Triangle.hpp:303
constexpr void invert()
Definition Triangle.hpp:807
constexpr LineSegment< t_dims, t_type, t_vertex > edge(TriangleLocation location) const
Edges the given location.
Definition Triangle.hpp:279
constexpr Angle< t_angle_type > angle(TriangleLocation location) const
Definition Triangle.hpp:339
constexpr TriangleLocation sharesObject(TriangleLocation object_to_check, const Triangle< t_dims, t_type, t_vertex > &tri, t_type epsilon=0) const
Definition Triangle.hpp:533
constexpr t_area_type area() const
Definition Triangle.hpp:361
constexpr bool contains(const t_vertex &vertex_point, t_type epsilon=t_type(0.0001)) const
Definition Triangle.hpp:479
constexpr Vector< t_dims, t_normal_type > normal() const
Definition Triangle.hpp:425
constexpr const t_vertex & vertex(uint01 triangle_node) const
Definition Triangle.hpp:239
constexpr LineSegment< t_dims, t_type, t_vertex > edge(uint01 triangle_node_a, uint01 triangle_node_b) const
Definition Triangle.hpp:260
constexpr t_vertex centroid() const
Definition Triangle.hpp:376
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
Definition Vector.hpp:62
constexpr Vector< t_dims, t_norm_type > normalized(Vector< t_dims, t_norm_type > value_if_nan=Constant< Vector< t_dims, t_norm_type > >::Invalid) const
Gets the normalized, or unit length representation of this vector.
Definition Vector.hpp:486
constexpr t_type magnitudeSquared() const
Vectors are commonly used to model forces such as wind, sea current, gravity, and electromagnetism.
Definition Vector.hpp:448
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.
Definition Angle.h:398
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
constexpr HSLColor Constant< HSLColor >::Invalid
The invalid HSLColor constant with all components set to invalid.
Definition HSLColor.h:264
double fltp08
Defines an alias representing an 8 byte floating-point number.
TriangleLocation
Values that represent triangle locations.
Definition Triangle.hpp:47
@ RADIANS
Angle measured in radians (0 to 2*PI for a full circle).
Definition Angle.h:57
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.
Definition Angle.h:388
t_type sqrt(const t_type &value)
constexpr bool Equals(const Triangle< t_dims, t_type, t_vertex > &tri_a, const Triangle< t_dims, t_type, t_vertex > &tri_b, t_type epsilon=0)
Definition Triangle.hpp:981
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type tan(const Angle< t_type > &angle)
Performs optimized tangent operation on the given angle using pre-computed lookup table for optimal s...
constexpr bool equals(const LineSegment< t_dims, t_type, t_vertex > &left, const LineSegment< t_dims, t_type, t_vertex > &right, const t_type &epsilon=cast< t_type >(0))
Tests if objects are considered equal.
Definition Line.hpp:791
constexpr t_type clip(const t_type &value, const t_type &lower_bound, const t_type &upper_bound)
Clips the value given so that that the returned value falls between upper and lower bound.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408