summaryrefslogtreecommitdiffhomepage
path: root/third-party/Opcode/Ice/IceTriangle.cpp
blob: e55f73e30f69010f724694a25588a3571132972f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains a handy triangle class.
 *	\file		IceTriangle.cpp
 *	\author		Pierre Terdiman
 *	\date		January, 17, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "StdAfx.h"

using namespace IceMaths;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains a triangle class.
 *
 *	\class		Tri
 *	\author		Pierre Terdiman
 *	\version	1.0
 *	\date		08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static sdword VPlaneSideEps(const IcePoint& v, const IcePlane& plane, float epsilon)
{
	// Compute distance from current vertex to the plane
	float Dist = plane.Distance(v);
	// Compute side:
	// 1	= the vertex is on the positive side of the plane
	// -1	= the vertex is on the negative side of the plane
	// 0	= the vertex is on the plane (within epsilon)
	return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flips the winding order.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Flip()
{
	IcePoint Tmp = mVerts[1];
	mVerts[1] = mVerts[2];
	mVerts[2] = Tmp;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle area.
 *	\return		the area
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Area() const
{
	const IcePoint& p0 = mVerts[0];
	const IcePoint& p1 = mVerts[1];
	const IcePoint& p2 = mVerts[2];
	return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle perimeter.
 *	\return		the perimeter
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Perimeter()	const
{
	const IcePoint& p0 = mVerts[0];
	const IcePoint& p1 = mVerts[1];
	const IcePoint& p2 = mVerts[2];
	return		p0.Distance(p1)
			+	p0.Distance(p2)
			+	p1.Distance(p2);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle compacity.
 *	\return		the compacity
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Compacity() const
{
	float P = Perimeter();
	if(P==0.0f)	return 0.0f;
	return (4.0f*PI*Area()/(P*P));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle normal.
 *	\param		normal	[out] the computed normal
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Normal(IcePoint& normal) const
{
	const IcePoint& p0 = mVerts[0];
	const IcePoint& p1 = mVerts[1];
	const IcePoint& p2 = mVerts[2];
	normal = ((p0 - p1)^(p0 - p2)).Normalize();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle denormalized normal.
 *	\param		normal	[out] the computed normal
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::DenormalizedNormal(IcePoint& normal) const
{
	const IcePoint& p0 = mVerts[0];
	const IcePoint& p1 = mVerts[1];
	const IcePoint& p2 = mVerts[2];
	normal = ((p0 - p1)^(p0 - p2));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle center.
 *	\param		center	[out] the computed center
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Center(IcePoint& center) const
{
	const IcePoint& p0 = mVerts[0];
	const IcePoint& p1 = mVerts[1];
	const IcePoint& p2 = mVerts[2];
	center = (p0 + p1 + p2)*INV3;
}

PartVal Triangle::TestAgainstPlane(const IcePlane& plane, float epsilon) const
{
	bool Pos = false, Neg = false;

	// Loop through all vertices
	for(udword i=0;i<3;i++)
	{
		// Compute side:
		sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon);

				if (Side < 0)	Neg = true;
		else	if (Side > 0)	Pos = true;
	}

			if (!Pos && !Neg)	return TRI_ON_PLANE;
	else	if (Pos && Neg)		return TRI_INTERSECT;
	else	if (Pos && !Neg)	return TRI_PLUS_SPACE;
	else	if (!Pos && Neg)	return TRI_MINUS_SPACE;

	// What?!
	return TRI_FORCEDWORD;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle moment.
 *	\param		m	[out] the moment
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void Triangle::ComputeMoment(Moment& m)
{
	// Compute the area of the triangle
	m.mArea = Area();

	// Compute the centroid
	Center(m.mCentroid);

	// Second-order components. Handle zero-area faces.
	IcePoint& p = mVerts[0];
	IcePoint& q = mVerts[1];
	IcePoint& r = mVerts[2];
	if(m.mArea==0.0f)
	{
		// This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the 
		// sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices.
		m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x);
		m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y);
		m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z);
		m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y);
		m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z);
		m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z);      
		m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
		m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
		m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
	}
	else
	{
		const float OneOverTwelve = 1.0f / 12.0f;
		m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve;
		m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve;
		m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve;
		m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve;
		m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve;
		m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve;
		m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
		m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
		m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
	}
}
*/

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle's smallest edge length.
 *	\return		the smallest edge length
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MinEdgeLength()	const
{
	float Min = MAX_FLOAT;
	float Length01 = mVerts[0].Distance(mVerts[1]);
	float Length02 = mVerts[0].Distance(mVerts[2]);
	float Length12 = mVerts[1].Distance(mVerts[2]);
	if(Length01 < Min)	Min = Length01;
	if(Length02 < Min)	Min = Length02;
	if(Length12 < Min)	Min = Length12;
	return Min;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes the triangle's largest edge length.
 *	\return		the largest edge length
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MaxEdgeLength()	const
{
	float Max = MIN_FLOAT;
	float Length01 = mVerts[0].Distance(mVerts[1]);
	float Length02 = mVerts[0].Distance(mVerts[2]);
	float Length12 = mVerts[1].Distance(mVerts[2]);
	if(Length01 > Max)	Max = Length01;
	if(Length02 > Max)	Max = Length02;
	if(Length12 > Max)	Max = Length12;
	return Max;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Computes a IcePoint on the triangle according to the stabbing information.
 *	\param		u,v			[in] IcePoint's barycentric coordinates
 *	\param		pt			[out] IcePoint on triangle
 *	\param		nearvtx		[out] index of nearest vertex
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::ComputePoint(float u, float v, IcePoint& pt, udword* nearvtx)	const
{
	// Compute IcePoint coordinates
	pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2];

	// Compute nearest vertex if needed
	if(nearvtx)
	{
		// Compute distance vector
		IcePoint d(mVerts[0].SquareDistance(pt),	// Distance^2 from vertex 0 to IcePoint on the face
				mVerts[1].SquareDistance(pt),	// Distance^2 from vertex 1 to IcePoint on the face
				mVerts[2].SquareDistance(pt));	// Distance^2 from vertex 2 to IcePoint on the face

		// Get smallest distance
		*nearvtx = d.SmallestAxis();
	}
}

void Triangle::Inflate(float fat_coeff, bool constant_border)
{
	// Compute triangle center
	IcePoint TriangleCenter;
	Center(TriangleCenter);

	// Don't normalize?
	// Normalize => add a constant border, regardless of triangle size
	// Don't => add more to big triangles
	for(udword i=0;i<3;i++)
	{
		IcePoint v = mVerts[i] - TriangleCenter;

		if(constant_border)	v.Normalize();

		mVerts[i] += v * fat_coeff;
	}
}