xref: /TaskScheduler/ThirdParty/Squish/maths.cpp (revision 2f083884)
1*2f083884Ss.makeev_local /* -----------------------------------------------------------------------------
2*2f083884Ss.makeev_local 
3*2f083884Ss.makeev_local 	Copyright (c) 2006 Simon Brown                          [email protected]
4*2f083884Ss.makeev_local 
5*2f083884Ss.makeev_local 	Permission is hereby granted, free of charge, to any person obtaining
6*2f083884Ss.makeev_local 	a copy of this software and associated documentation files (the
7*2f083884Ss.makeev_local 	"Software"), to	deal in the Software without restriction, including
8*2f083884Ss.makeev_local 	without limitation the rights to use, copy, modify, merge, publish,
9*2f083884Ss.makeev_local 	distribute, sublicense, and/or sell copies of the Software, and to
10*2f083884Ss.makeev_local 	permit persons to whom the Software is furnished to do so, subject to
11*2f083884Ss.makeev_local 	the following conditions:
12*2f083884Ss.makeev_local 
13*2f083884Ss.makeev_local 	The above copyright notice and this permission notice shall be included
14*2f083884Ss.makeev_local 	in all copies or substantial portions of the Software.
15*2f083884Ss.makeev_local 
16*2f083884Ss.makeev_local 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*2f083884Ss.makeev_local 	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*2f083884Ss.makeev_local 	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19*2f083884Ss.makeev_local 	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20*2f083884Ss.makeev_local 	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21*2f083884Ss.makeev_local 	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22*2f083884Ss.makeev_local 	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*2f083884Ss.makeev_local 
24*2f083884Ss.makeev_local    -------------------------------------------------------------------------- */
25*2f083884Ss.makeev_local 
26*2f083884Ss.makeev_local /*! @file
27*2f083884Ss.makeev_local 
28*2f083884Ss.makeev_local 	The symmetric eigensystem solver algorithm is from
29*2f083884Ss.makeev_local 	http://www.geometrictools.com/Documentation/EigenSymmetric3x3.pdf
30*2f083884Ss.makeev_local */
31*2f083884Ss.makeev_local 
32*2f083884Ss.makeev_local #include "maths.h"
33*2f083884Ss.makeev_local #include <cfloat>
34*2f083884Ss.makeev_local 
35*2f083884Ss.makeev_local namespace squish {
36*2f083884Ss.makeev_local 
ComputeWeightedCovariance(int n,Vec3 const * points,float const * weights)37*2f083884Ss.makeev_local Sym3x3 ComputeWeightedCovariance( int n, Vec3 const* points, float const* weights )
38*2f083884Ss.makeev_local {
39*2f083884Ss.makeev_local 	// compute the centroid
40*2f083884Ss.makeev_local 	float total = 0.0f;
41*2f083884Ss.makeev_local 	Vec3 centroid( 0.0f );
42*2f083884Ss.makeev_local 	for( int i = 0; i < n; ++i )
43*2f083884Ss.makeev_local 	{
44*2f083884Ss.makeev_local 		total += weights[i];
45*2f083884Ss.makeev_local 		centroid += weights[i]*points[i];
46*2f083884Ss.makeev_local 	}
47*2f083884Ss.makeev_local 	centroid /= total;
48*2f083884Ss.makeev_local 
49*2f083884Ss.makeev_local 	// accumulate the covariance matrix
50*2f083884Ss.makeev_local 	Sym3x3 covariance( 0.0f );
51*2f083884Ss.makeev_local 	for( int i = 0; i < n; ++i )
52*2f083884Ss.makeev_local 	{
53*2f083884Ss.makeev_local 		Vec3 a = points[i] - centroid;
54*2f083884Ss.makeev_local 		Vec3 b = weights[i]*a;
55*2f083884Ss.makeev_local 
56*2f083884Ss.makeev_local 		covariance[0] += a.X()*b.X();
57*2f083884Ss.makeev_local 		covariance[1] += a.X()*b.Y();
58*2f083884Ss.makeev_local 		covariance[2] += a.X()*b.Z();
59*2f083884Ss.makeev_local 		covariance[3] += a.Y()*b.Y();
60*2f083884Ss.makeev_local 		covariance[4] += a.Y()*b.Z();
61*2f083884Ss.makeev_local 		covariance[5] += a.Z()*b.Z();
62*2f083884Ss.makeev_local 	}
63*2f083884Ss.makeev_local 
64*2f083884Ss.makeev_local 	// return it
65*2f083884Ss.makeev_local 	return covariance;
66*2f083884Ss.makeev_local }
67*2f083884Ss.makeev_local 
GetMultiplicity1Evector(Sym3x3 const & matrix,float evalue)68*2f083884Ss.makeev_local static Vec3 GetMultiplicity1Evector( Sym3x3 const& matrix, float evalue )
69*2f083884Ss.makeev_local {
70*2f083884Ss.makeev_local 	// compute M
71*2f083884Ss.makeev_local 	Sym3x3 m;
72*2f083884Ss.makeev_local 	m[0] = matrix[0] - evalue;
73*2f083884Ss.makeev_local 	m[1] = matrix[1];
74*2f083884Ss.makeev_local 	m[2] = matrix[2];
75*2f083884Ss.makeev_local 	m[3] = matrix[3] - evalue;
76*2f083884Ss.makeev_local 	m[4] = matrix[4];
77*2f083884Ss.makeev_local 	m[5] = matrix[5] - evalue;
78*2f083884Ss.makeev_local 
79*2f083884Ss.makeev_local 	// compute U
80*2f083884Ss.makeev_local 	Sym3x3 u;
81*2f083884Ss.makeev_local 	u[0] = m[3]*m[5] - m[4]*m[4];
82*2f083884Ss.makeev_local 	u[1] = m[2]*m[4] - m[1]*m[5];
83*2f083884Ss.makeev_local 	u[2] = m[1]*m[4] - m[2]*m[3];
84*2f083884Ss.makeev_local 	u[3] = m[0]*m[5] - m[2]*m[2];
85*2f083884Ss.makeev_local 	u[4] = m[1]*m[2] - m[4]*m[0];
86*2f083884Ss.makeev_local 	u[5] = m[0]*m[3] - m[1]*m[1];
87*2f083884Ss.makeev_local 
88*2f083884Ss.makeev_local 	// find the largest component
89*2f083884Ss.makeev_local 	float mc = std::fabs( u[0] );
90*2f083884Ss.makeev_local 	int mi = 0;
91*2f083884Ss.makeev_local 	for( int i = 1; i < 6; ++i )
92*2f083884Ss.makeev_local 	{
93*2f083884Ss.makeev_local 		float c = std::fabs( u[i] );
94*2f083884Ss.makeev_local 		if( c > mc )
95*2f083884Ss.makeev_local 		{
96*2f083884Ss.makeev_local 			mc = c;
97*2f083884Ss.makeev_local 			mi = i;
98*2f083884Ss.makeev_local 		}
99*2f083884Ss.makeev_local 	}
100*2f083884Ss.makeev_local 
101*2f083884Ss.makeev_local 	// pick the column with this component
102*2f083884Ss.makeev_local 	switch( mi )
103*2f083884Ss.makeev_local 	{
104*2f083884Ss.makeev_local 	case 0:
105*2f083884Ss.makeev_local 		return Vec3( u[0], u[1], u[2] );
106*2f083884Ss.makeev_local 
107*2f083884Ss.makeev_local 	case 1:
108*2f083884Ss.makeev_local 	case 3:
109*2f083884Ss.makeev_local 		return Vec3( u[1], u[3], u[4] );
110*2f083884Ss.makeev_local 
111*2f083884Ss.makeev_local 	default:
112*2f083884Ss.makeev_local 		return Vec3( u[2], u[4], u[5] );
113*2f083884Ss.makeev_local 	}
114*2f083884Ss.makeev_local }
115*2f083884Ss.makeev_local 
GetMultiplicity2Evector(Sym3x3 const & matrix,float evalue)116*2f083884Ss.makeev_local static Vec3 GetMultiplicity2Evector( Sym3x3 const& matrix, float evalue )
117*2f083884Ss.makeev_local {
118*2f083884Ss.makeev_local 	// compute M
119*2f083884Ss.makeev_local 	Sym3x3 m;
120*2f083884Ss.makeev_local 	m[0] = matrix[0] - evalue;
121*2f083884Ss.makeev_local 	m[1] = matrix[1];
122*2f083884Ss.makeev_local 	m[2] = matrix[2];
123*2f083884Ss.makeev_local 	m[3] = matrix[3] - evalue;
124*2f083884Ss.makeev_local 	m[4] = matrix[4];
125*2f083884Ss.makeev_local 	m[5] = matrix[5] - evalue;
126*2f083884Ss.makeev_local 
127*2f083884Ss.makeev_local 	// find the largest component
128*2f083884Ss.makeev_local 	float mc = std::fabs( m[0] );
129*2f083884Ss.makeev_local 	int mi = 0;
130*2f083884Ss.makeev_local 	for( int i = 1; i < 6; ++i )
131*2f083884Ss.makeev_local 	{
132*2f083884Ss.makeev_local 		float c = std::fabs( m[i] );
133*2f083884Ss.makeev_local 		if( c > mc )
134*2f083884Ss.makeev_local 		{
135*2f083884Ss.makeev_local 			mc = c;
136*2f083884Ss.makeev_local 			mi = i;
137*2f083884Ss.makeev_local 		}
138*2f083884Ss.makeev_local 	}
139*2f083884Ss.makeev_local 
140*2f083884Ss.makeev_local 	// pick the first eigenvector based on this index
141*2f083884Ss.makeev_local 	switch( mi )
142*2f083884Ss.makeev_local 	{
143*2f083884Ss.makeev_local 	case 0:
144*2f083884Ss.makeev_local 	case 1:
145*2f083884Ss.makeev_local 		return Vec3( -m[1], m[0], 0.0f );
146*2f083884Ss.makeev_local 
147*2f083884Ss.makeev_local 	case 2:
148*2f083884Ss.makeev_local 		return Vec3( m[2], 0.0f, -m[0] );
149*2f083884Ss.makeev_local 
150*2f083884Ss.makeev_local 	case 3:
151*2f083884Ss.makeev_local 	case 4:
152*2f083884Ss.makeev_local 		return Vec3( 0.0f, -m[4], m[3] );
153*2f083884Ss.makeev_local 
154*2f083884Ss.makeev_local 	default:
155*2f083884Ss.makeev_local 		return Vec3( 0.0f, -m[5], m[4] );
156*2f083884Ss.makeev_local 	}
157*2f083884Ss.makeev_local }
158*2f083884Ss.makeev_local 
ComputePrincipleComponent(Sym3x3 const & matrix)159*2f083884Ss.makeev_local Vec3 ComputePrincipleComponent( Sym3x3 const& matrix )
160*2f083884Ss.makeev_local {
161*2f083884Ss.makeev_local 	// compute the cubic coefficients
162*2f083884Ss.makeev_local 	float c0 = matrix[0]*matrix[3]*matrix[5]
163*2f083884Ss.makeev_local 		+ 2.0f*matrix[1]*matrix[2]*matrix[4]
164*2f083884Ss.makeev_local 		- matrix[0]*matrix[4]*matrix[4]
165*2f083884Ss.makeev_local 		- matrix[3]*matrix[2]*matrix[2]
166*2f083884Ss.makeev_local 		- matrix[5]*matrix[1]*matrix[1];
167*2f083884Ss.makeev_local 	float c1 = matrix[0]*matrix[3] + matrix[0]*matrix[5] + matrix[3]*matrix[5]
168*2f083884Ss.makeev_local 		- matrix[1]*matrix[1] - matrix[2]*matrix[2] - matrix[4]*matrix[4];
169*2f083884Ss.makeev_local 	float c2 = matrix[0] + matrix[3] + matrix[5];
170*2f083884Ss.makeev_local 
171*2f083884Ss.makeev_local 	// compute the quadratic coefficients
172*2f083884Ss.makeev_local 	float a = c1 - ( 1.0f/3.0f )*c2*c2;
173*2f083884Ss.makeev_local 	float b = ( -2.0f/27.0f )*c2*c2*c2 + ( 1.0f/3.0f )*c1*c2 - c0;
174*2f083884Ss.makeev_local 
175*2f083884Ss.makeev_local 	// compute the root count check
176*2f083884Ss.makeev_local 	float Q = 0.25f*b*b + ( 1.0f/27.0f )*a*a*a;
177*2f083884Ss.makeev_local 
178*2f083884Ss.makeev_local 	// test the multiplicity
179*2f083884Ss.makeev_local 	if( FLT_EPSILON < Q )
180*2f083884Ss.makeev_local 	{
181*2f083884Ss.makeev_local 		// only one root, which implies we have a multiple of the identity
182*2f083884Ss.makeev_local         return Vec3( 1.0f );
183*2f083884Ss.makeev_local 	}
184*2f083884Ss.makeev_local 	else if( Q < -FLT_EPSILON )
185*2f083884Ss.makeev_local 	{
186*2f083884Ss.makeev_local 		// three distinct roots
187*2f083884Ss.makeev_local 		float theta = std::atan2( std::sqrt( -Q ), -0.5f*b );
188*2f083884Ss.makeev_local 		float rho = std::sqrt( 0.25f*b*b - Q );
189*2f083884Ss.makeev_local 
190*2f083884Ss.makeev_local 		float rt = std::pow( rho, 1.0f/3.0f );
191*2f083884Ss.makeev_local 		float ct = std::cos( theta/3.0f );
192*2f083884Ss.makeev_local 		float st = std::sin( theta/3.0f );
193*2f083884Ss.makeev_local 
194*2f083884Ss.makeev_local 		float l1 = ( 1.0f/3.0f )*c2 + 2.0f*rt*ct;
195*2f083884Ss.makeev_local 		float l2 = ( 1.0f/3.0f )*c2 - rt*( ct + ( float )sqrt( 3.0f )*st );
196*2f083884Ss.makeev_local 		float l3 = ( 1.0f/3.0f )*c2 - rt*( ct - ( float )sqrt( 3.0f )*st );
197*2f083884Ss.makeev_local 
198*2f083884Ss.makeev_local 		// pick the larger
199*2f083884Ss.makeev_local 		if( std::fabs( l2 ) > std::fabs( l1 ) )
200*2f083884Ss.makeev_local 			l1 = l2;
201*2f083884Ss.makeev_local 		if( std::fabs( l3 ) > std::fabs( l1 ) )
202*2f083884Ss.makeev_local 			l1 = l3;
203*2f083884Ss.makeev_local 
204*2f083884Ss.makeev_local 		// get the eigenvector
205*2f083884Ss.makeev_local 		return GetMultiplicity1Evector( matrix, l1 );
206*2f083884Ss.makeev_local 	}
207*2f083884Ss.makeev_local 	else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON )
208*2f083884Ss.makeev_local 	{
209*2f083884Ss.makeev_local 		// two roots
210*2f083884Ss.makeev_local 		float rt;
211*2f083884Ss.makeev_local 		if( b < 0.0f )
212*2f083884Ss.makeev_local 			rt = -std::pow( -0.5f*b, 1.0f/3.0f );
213*2f083884Ss.makeev_local 		else
214*2f083884Ss.makeev_local 			rt = std::pow( 0.5f*b, 1.0f/3.0f );
215*2f083884Ss.makeev_local 
216*2f083884Ss.makeev_local 		float l1 = ( 1.0f/3.0f )*c2 + rt;		// repeated
217*2f083884Ss.makeev_local 		float l2 = ( 1.0f/3.0f )*c2 - 2.0f*rt;
218*2f083884Ss.makeev_local 
219*2f083884Ss.makeev_local 		// get the eigenvector
220*2f083884Ss.makeev_local 		if( std::fabs( l1 ) > std::fabs( l2 ) )
221*2f083884Ss.makeev_local 			return GetMultiplicity2Evector( matrix, l1 );
222*2f083884Ss.makeev_local 		else
223*2f083884Ss.makeev_local 			return GetMultiplicity1Evector( matrix, l2 );
224*2f083884Ss.makeev_local 	}
225*2f083884Ss.makeev_local }
226*2f083884Ss.makeev_local 
227*2f083884Ss.makeev_local } // namespace squish
228