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