1 module des.math.linear.triangle;
2 
3 import std.traits;
4 import des.math.linear.vector;
5 import des.math.linear.matrix;
6 import des.math.linear.ray;
7 import des.math.basic;
8 
9 ///
10 struct Triangle(T) if( isFloatingPoint!T )
11 {
12     ///
13     alias Vector3!T vectype;
14 
15     ///
16     vectype[3] pnt;
17 
18 pure:
19 
20     ///
21     this( in vectype P0, in vectype P1, in vectype P2 )
22     {
23         pnt[0] = P0;
24         pnt[1] = P1;
25         pnt[2] = P2;
26     }
27 
28     @property
29     {
30         ///
31         vectype perp() const { return cross( pnt[1]-pnt[0], pnt[2]-pnt[0] ); }
32         ///
33         vectype norm() const { return perp.e; }
34         ///
35         T area() const { return perp.len / 2.0; }
36         ///
37         vectype center() const { return (pnt[0] + pnt[1] + pnt[2]) / 3.0f; }
38     }
39 
40     /// affine transform
41     auto tr(X)( in Matrix!(4,4,X) mtr ) const
42     {
43         return Triangle!T( (mtr * vec!(4,T,"x y z w")( pnt[0], 1 )).xyz,
44                            (mtr * vec!(4,T,"x y z w")( pnt[1], 1 )).xyz,
45                            (mtr * vec!(4,T,"x y z w")( pnt[2], 1 )).xyz );
46     }
47 
48     ///
49     Ray!(T)[3] toRays() const
50     {
51         alias Ray!T st;
52         return [ st.fromPoints( pnt[0], pnt[1] ),
53                  st.fromPoints( pnt[1], pnt[2] ),
54                  st.fromPoints( pnt[2], pnt[0] ) ];
55     }
56 
57     /+ высота проведённая из точки это отрезок, 
58        соединяющий проекцию точки на плоскость и 
59        саму точку (Ray) +/
60     ///
61     auto altitude( in vectype pp ) const
62     {
63         auto n = norm;
64         auto dst = n * dot( n, pp-pnt[0] );
65         return Ray!T( pp - dst, dst );
66     }
67 
68     ///
69     auto project(F)( in Ray!F seg ) const
70     {
71         auto n = norm;
72         auto dst1 = dot( n, seg.pos-pnt[0] );
73         auto dst2 = dot( n, seg.end-pnt[0] );
74         auto diff = dst1 - dst2;
75         return Ray!T( seg.png - n * dst1,
76                           seg.dir + n * diff );
77     }
78 
79     ///
80     auto intersect(F)( in Ray!F seg ) const
81     { return seg.intersect( project(seg) ); }
82 }
83 
84 ///
85 alias Triangle!float  fTriangle;
86 ///
87 alias Triangle!double dTriangle;
88 ///
89 alias Triangle!real   rTriangle;
90 
91 ///
92 unittest
93 {
94     auto poly = fTriangle( vec3(0,0,0), vec3(1,0,0), vec3(0,1,0) );
95     assert( poly.area == 0.5f );
96     assert( poly.norm == vec3(0,0,1) );
97 
98     auto pnt = vec3( 2,2,2 );
99     auto a = poly.altitude( pnt );
100     assert( a.pos == vec3(2,2,0) );
101     assert( a.dir == vec3(0,0,2) );
102 }