1 | // a set of routines that let you do common 3d math |
2 | // operations without any vector, matrix, or quaternion |
3 | // classes or templates. |
4 | // |
5 | // a vector (or point) is a 'float *' to 3 floating point numbers. |
6 | // a matrix is a 'float *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL |
7 | // a quaternion is a 'float *' to 4 floats representing a quaternion x,y,z,w |
8 | // |
9 | |
10 | #ifdef _MSC_VER |
11 | #pragma warning(disable:4996) |
12 | #endif |
13 | |
14 | namespace FLOAT_MATH |
15 | { |
16 | |
17 | void fm_inverseRT(const REAL matrix[16],const REAL pos[3],REAL t[3]) // inverse rotate translate the point. |
18 | { |
19 | |
20 | REAL _x = pos[0] - matrix[3*4+0]; |
21 | REAL _y = pos[1] - matrix[3*4+1]; |
22 | REAL _z = pos[2] - matrix[3*4+2]; |
23 | |
24 | // Multiply inverse-translated source vector by inverted rotation transform |
25 | |
26 | t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z); |
27 | t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z); |
28 | t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z); |
29 | |
30 | } |
31 | |
32 | REAL fm_getDeterminant(const REAL matrix[16]) |
33 | { |
34 | REAL tempv[3]; |
35 | REAL p0[3]; |
36 | REAL p1[3]; |
37 | REAL p2[3]; |
38 | |
39 | |
40 | p0[0] = matrix[0*4+0]; |
41 | p0[1] = matrix[0*4+1]; |
42 | p0[2] = matrix[0*4+2]; |
43 | |
44 | p1[0] = matrix[1*4+0]; |
45 | p1[1] = matrix[1*4+1]; |
46 | p1[2] = matrix[1*4+2]; |
47 | |
48 | p2[0] = matrix[2*4+0]; |
49 | p2[1] = matrix[2*4+1]; |
50 | p2[2] = matrix[2*4+2]; |
51 | |
52 | fm_cross(tempv,p1,p2); |
53 | |
54 | return fm_dot(p0,tempv); |
55 | |
56 | } |
57 | |
58 | REAL fm_squared(REAL x) { return x*x; }; |
59 | |
60 | void fm_decomposeTransform(const REAL local_transform[16],REAL trans[3],REAL rot[4],REAL scale[3]) |
61 | { |
62 | |
63 | trans[0] = local_transform[12]; |
64 | trans[1] = local_transform[13]; |
65 | trans[2] = local_transform[14]; |
66 | |
67 | scale[0] = (REAL)sqrt(fm_squared(local_transform[0*4+0]) + fm_squared(local_transform[0*4+1]) + fm_squared(local_transform[0*4+2])); |
68 | scale[1] = (REAL)sqrt(fm_squared(local_transform[1*4+0]) + fm_squared(local_transform[1*4+1]) + fm_squared(local_transform[1*4+2])); |
69 | scale[2] = (REAL)sqrt(fm_squared(local_transform[2*4+0]) + fm_squared(local_transform[2*4+1]) + fm_squared(local_transform[2*4+2])); |
70 | |
71 | REAL m[16]; |
72 | memcpy(m,local_transform,sizeof(REAL)*16); |
73 | |
74 | REAL sx = 1.0f / scale[0]; |
75 | REAL sy = 1.0f / scale[1]; |
76 | REAL sz = 1.0f / scale[2]; |
77 | |
78 | m[0*4+0]*=sx; |
79 | m[0*4+1]*=sx; |
80 | m[0*4+2]*=sx; |
81 | |
82 | m[1*4+0]*=sy; |
83 | m[1*4+1]*=sy; |
84 | m[1*4+2]*=sy; |
85 | |
86 | m[2*4+0]*=sz; |
87 | m[2*4+1]*=sz; |
88 | m[2*4+2]*=sz; |
89 | |
90 | fm_matrixToQuat(m,rot); |
91 | |
92 | } |
93 | |
94 | void fm_getSubMatrix(int32_t ki,int32_t kj,REAL pDst[16],const REAL matrix[16]) |
95 | { |
96 | int32_t row, col; |
97 | int32_t dstCol = 0, dstRow = 0; |
98 | |
99 | for ( col = 0; col < 4; col++ ) |
100 | { |
101 | if ( col == kj ) |
102 | { |
103 | continue; |
104 | } |
105 | for ( dstRow = 0, row = 0; row < 4; row++ ) |
106 | { |
107 | if ( row == ki ) |
108 | { |
109 | continue; |
110 | } |
111 | pDst[dstCol*4+dstRow] = matrix[col*4+row]; |
112 | dstRow++; |
113 | } |
114 | dstCol++; |
115 | } |
116 | } |
117 | |
118 | void fm_inverseTransform(const REAL matrix[16],REAL inverse_matrix[16]) |
119 | { |
120 | REAL determinant = fm_getDeterminant(matrix); |
121 | determinant = 1.0f / determinant; |
122 | for (int32_t i = 0; i < 4; i++ ) |
123 | { |
124 | for (int32_t j = 0; j < 4; j++ ) |
125 | { |
126 | int32_t sign = 1 - ( ( i + j ) % 2 ) * 2; |
127 | REAL subMat[16]; |
128 | fm_identity(subMat); |
129 | fm_getSubMatrix( i, j, subMat, matrix ); |
130 | REAL subDeterminant = fm_getDeterminant(subMat); |
131 | inverse_matrix[i*4+j] = ( subDeterminant * sign ) * determinant; |
132 | } |
133 | } |
134 | } |
135 | |
136 | void fm_identity(REAL matrix[16]) // set 4x4 matrix to identity. |
137 | { |
138 | matrix[0*4+0] = 1; |
139 | matrix[1*4+1] = 1; |
140 | matrix[2*4+2] = 1; |
141 | matrix[3*4+3] = 1; |
142 | |
143 | matrix[1*4+0] = 0; |
144 | matrix[2*4+0] = 0; |
145 | matrix[3*4+0] = 0; |
146 | |
147 | matrix[0*4+1] = 0; |
148 | matrix[2*4+1] = 0; |
149 | matrix[3*4+1] = 0; |
150 | |
151 | matrix[0*4+2] = 0; |
152 | matrix[1*4+2] = 0; |
153 | matrix[3*4+2] = 0; |
154 | |
155 | matrix[0*4+3] = 0; |
156 | matrix[1*4+3] = 0; |
157 | matrix[2*4+3] = 0; |
158 | |
159 | } |
160 | |
161 | void fm_quatToEuler(const REAL quat[4],REAL &ax,REAL &ay,REAL &az) |
162 | { |
163 | REAL x = quat[0]; |
164 | REAL y = quat[1]; |
165 | REAL z = quat[2]; |
166 | REAL w = quat[3]; |
167 | |
168 | REAL sint = (2.0f * w * y) - (2.0f * x * z); |
169 | REAL cost_temp = 1.0f - (sint * sint); |
170 | REAL cost = 0; |
171 | |
172 | if ( (REAL)fabs(cost_temp) > 0.001f ) |
173 | { |
174 | cost = (REAL)sqrt( cost_temp ); |
175 | } |
176 | |
177 | REAL sinv, cosv, sinf, cosf; |
178 | if ( (REAL)fabs(cost) > 0.001f ) |
179 | { |
180 | cost = 1.0f / cost; |
181 | sinv = ((2.0f * y * z) + (2.0f * w * x)) * cost; |
182 | cosv = (1.0f - (2.0f * x * x) - (2.0f * y * y)) * cost; |
183 | sinf = ((2.0f * x * y) + (2.0f * w * z)) * cost; |
184 | cosf = (1.0f - (2.0f * y * y) - (2.0f * z * z)) * cost; |
185 | } |
186 | else |
187 | { |
188 | sinv = (2.0f * w * x) - (2.0f * y * z); |
189 | cosv = 1.0f - (2.0f * x * x) - (2.0f * z * z); |
190 | sinf = 0; |
191 | cosf = 1.0f; |
192 | } |
193 | |
194 | // compute output rotations |
195 | ax = (REAL)atan2( sinv, cosv ); |
196 | ay = (REAL)atan2( sint, cost ); |
197 | az = (REAL)atan2( sinf, cosf ); |
198 | |
199 | } |
200 | |
201 | void fm_eulerToMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) |
202 | { |
203 | REAL quat[4]; |
204 | fm_eulerToQuat(ax,ay,az,quat); |
205 | fm_quatToMatrix(quat,matrix); |
206 | } |
207 | |
208 | void fm_getAABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *bmin,REAL *bmax) |
209 | { |
210 | |
211 | const uint8_t *source = (const uint8_t *) points; |
212 | |
213 | bmin[0] = points[0]; |
214 | bmin[1] = points[1]; |
215 | bmin[2] = points[2]; |
216 | |
217 | bmax[0] = points[0]; |
218 | bmax[1] = points[1]; |
219 | bmax[2] = points[2]; |
220 | |
221 | |
222 | for (uint32_t i=1; i<vcount; i++) |
223 | { |
224 | source+=pstride; |
225 | const REAL *p = (const REAL *) source; |
226 | |
227 | if ( p[0] < bmin[0] ) bmin[0] = p[0]; |
228 | if ( p[1] < bmin[1] ) bmin[1] = p[1]; |
229 | if ( p[2] < bmin[2] ) bmin[2] = p[2]; |
230 | |
231 | if ( p[0] > bmax[0] ) bmax[0] = p[0]; |
232 | if ( p[1] > bmax[1] ) bmax[1] = p[1]; |
233 | if ( p[2] > bmax[2] ) bmax[2] = p[2]; |
234 | |
235 | } |
236 | } |
237 | |
238 | void fm_eulerToQuat(const REAL *euler,REAL *quat) // convert euler angles to quaternion. |
239 | { |
240 | fm_eulerToQuat(euler[0],euler[1],euler[2],quat); |
241 | } |
242 | |
243 | void fm_eulerToQuat(REAL roll,REAL pitch,REAL yaw,REAL *quat) // convert euler angles to quaternion. |
244 | { |
245 | roll *= 0.5f; |
246 | pitch *= 0.5f; |
247 | yaw *= 0.5f; |
248 | |
249 | REAL cr = (REAL)cos(roll); |
250 | REAL cp = (REAL)cos(pitch); |
251 | REAL cy = (REAL)cos(yaw); |
252 | |
253 | REAL sr = (REAL)sin(roll); |
254 | REAL sp = (REAL)sin(pitch); |
255 | REAL sy = (REAL)sin(yaw); |
256 | |
257 | REAL cpcy = cp * cy; |
258 | REAL spsy = sp * sy; |
259 | REAL spcy = sp * cy; |
260 | REAL cpsy = cp * sy; |
261 | |
262 | quat[0] = ( sr * cpcy - cr * spsy); |
263 | quat[1] = ( cr * spcy + sr * cpsy); |
264 | quat[2] = ( cr * cpsy - sr * spcy); |
265 | quat[3] = cr * cpcy + sr * spsy; |
266 | } |
267 | |
268 | void fm_quatToMatrix(const REAL *quat,REAL *matrix) // convert quaterinion rotation to matrix, zeros out the translation component. |
269 | { |
270 | |
271 | REAL xx = quat[0]*quat[0]; |
272 | REAL yy = quat[1]*quat[1]; |
273 | REAL zz = quat[2]*quat[2]; |
274 | REAL xy = quat[0]*quat[1]; |
275 | REAL xz = quat[0]*quat[2]; |
276 | REAL yz = quat[1]*quat[2]; |
277 | REAL wx = quat[3]*quat[0]; |
278 | REAL wy = quat[3]*quat[1]; |
279 | REAL wz = quat[3]*quat[2]; |
280 | |
281 | matrix[0*4+0] = 1 - 2 * ( yy + zz ); |
282 | matrix[1*4+0] = 2 * ( xy - wz ); |
283 | matrix[2*4+0] = 2 * ( xz + wy ); |
284 | |
285 | matrix[0*4+1] = 2 * ( xy + wz ); |
286 | matrix[1*4+1] = 1 - 2 * ( xx + zz ); |
287 | matrix[2*4+1] = 2 * ( yz - wx ); |
288 | |
289 | matrix[0*4+2] = 2 * ( xz - wy ); |
290 | matrix[1*4+2] = 2 * ( yz + wx ); |
291 | matrix[2*4+2] = 1 - 2 * ( xx + yy ); |
292 | |
293 | matrix[3*4+0] = matrix[3*4+1] = matrix[3*4+2] = (REAL) 0.0f; |
294 | matrix[0*4+3] = matrix[1*4+3] = matrix[2*4+3] = (REAL) 0.0f; |
295 | matrix[3*4+3] =(REAL) 1.0f; |
296 | |
297 | } |
298 | |
299 | |
300 | void fm_quatRotate(const REAL *quat,const REAL *v,REAL *r) // rotate a vector directly by a quaternion. |
301 | { |
302 | REAL left[4]; |
303 | |
304 | left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2]; |
305 | left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0]; |
306 | left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1]; |
307 | left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2]; |
308 | |
309 | r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]); |
310 | r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]); |
311 | r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]); |
312 | |
313 | } |
314 | |
315 | |
316 | void fm_getTranslation(const REAL *matrix,REAL *t) |
317 | { |
318 | t[0] = matrix[3*4+0]; |
319 | t[1] = matrix[3*4+1]; |
320 | t[2] = matrix[3*4+2]; |
321 | } |
322 | |
323 | void fm_matrixToQuat(const REAL *matrix,REAL *quat) // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w |
324 | { |
325 | |
326 | REAL tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2]; |
327 | |
328 | // check the diagonal |
329 | |
330 | if (tr > 0.0f ) |
331 | { |
332 | REAL s = (REAL) sqrt ( (double) (tr + 1.0f) ); |
333 | quat[3] = s * 0.5f; |
334 | s = 0.5f / s; |
335 | quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s; |
336 | quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s; |
337 | quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s; |
338 | |
339 | } |
340 | else |
341 | { |
342 | // diagonal is negative |
343 | int32_t nxt[3] = {1, 2, 0}; |
344 | REAL qa[4]; |
345 | |
346 | int32_t i = 0; |
347 | |
348 | if (matrix[1*4+1] > matrix[0*4+0]) i = 1; |
349 | if (matrix[2*4+2] > matrix[i*4+i]) i = 2; |
350 | |
351 | int32_t j = nxt[i]; |
352 | int32_t k = nxt[j]; |
353 | |
354 | REAL s = (REAL)sqrt ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) ); |
355 | |
356 | qa[i] = s * 0.5f; |
357 | |
358 | if (s != 0.0f ) s = 0.5f / s; |
359 | |
360 | qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s; |
361 | qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s; |
362 | qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s; |
363 | |
364 | quat[0] = qa[0]; |
365 | quat[1] = qa[1]; |
366 | quat[2] = qa[2]; |
367 | quat[3] = qa[3]; |
368 | } |
369 | // fm_normalizeQuat(quat); |
370 | } |
371 | |
372 | |
373 | REAL fm_sphereVolume(REAL radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed ) |
374 | { |
375 | return (4.0f / 3.0f ) * FM_PI * radius * radius * radius; |
376 | } |
377 | |
378 | |
379 | REAL fm_cylinderVolume(REAL radius,REAL h) |
380 | { |
381 | return FM_PI * radius * radius *h; |
382 | } |
383 | |
384 | REAL fm_capsuleVolume(REAL radius,REAL h) |
385 | { |
386 | REAL volume = fm_sphereVolume(radius); // volume of the sphere portion. |
387 | REAL ch = h-radius*2; // this is the cylinder length |
388 | if ( ch > 0 ) |
389 | { |
390 | volume+=fm_cylinderVolume(radius,ch); |
391 | } |
392 | return volume; |
393 | } |
394 | |
395 | void fm_transform(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point |
396 | { |
397 | if ( matrix ) |
398 | { |
399 | REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0]; |
400 | REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1]; |
401 | REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2]; |
402 | t[0] = tx; |
403 | t[1] = ty; |
404 | t[2] = tz; |
405 | } |
406 | else |
407 | { |
408 | t[0] = v[0]; |
409 | t[1] = v[1]; |
410 | t[2] = v[2]; |
411 | } |
412 | } |
413 | |
414 | void fm_rotate(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point |
415 | { |
416 | if ( matrix ) |
417 | { |
418 | REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]); |
419 | REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]); |
420 | REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]); |
421 | t[0] = tx; |
422 | t[1] = ty; |
423 | t[2] = tz; |
424 | } |
425 | else |
426 | { |
427 | t[0] = v[0]; |
428 | t[1] = v[1]; |
429 | t[2] = v[2]; |
430 | } |
431 | } |
432 | |
433 | |
434 | REAL fm_distance(const REAL *p1,const REAL *p2) |
435 | { |
436 | REAL dx = p1[0] - p2[0]; |
437 | REAL dy = p1[1] - p2[1]; |
438 | REAL dz = p1[2] - p2[2]; |
439 | |
440 | return (REAL)sqrt( dx*dx + dy*dy + dz *dz ); |
441 | } |
442 | |
443 | REAL fm_distanceSquared(const REAL *p1,const REAL *p2) |
444 | { |
445 | REAL dx = p1[0] - p2[0]; |
446 | REAL dy = p1[1] - p2[1]; |
447 | REAL dz = p1[2] - p2[2]; |
448 | |
449 | return dx*dx + dy*dy + dz *dz; |
450 | } |
451 | |
452 | |
453 | REAL fm_distanceSquaredXZ(const REAL *p1,const REAL *p2) |
454 | { |
455 | REAL dx = p1[0] - p2[0]; |
456 | REAL dz = p1[2] - p2[2]; |
457 | |
458 | return dx*dx + dz *dz; |
459 | } |
460 | |
461 | |
462 | REAL fm_computePlane(const REAL *A,const REAL *B,const REAL *C,REAL *n) // returns D |
463 | { |
464 | REAL vx = (B[0] - C[0]); |
465 | REAL vy = (B[1] - C[1]); |
466 | REAL vz = (B[2] - C[2]); |
467 | |
468 | REAL wx = (A[0] - B[0]); |
469 | REAL wy = (A[1] - B[1]); |
470 | REAL wz = (A[2] - B[2]); |
471 | |
472 | REAL vw_x = vy * wz - vz * wy; |
473 | REAL vw_y = vz * wx - vx * wz; |
474 | REAL vw_z = vx * wy - vy * wx; |
475 | |
476 | REAL mag = (REAL)sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); |
477 | |
478 | if ( mag < 0.000001f ) |
479 | { |
480 | mag = 0; |
481 | } |
482 | else |
483 | { |
484 | mag = 1.0f/mag; |
485 | } |
486 | |
487 | REAL x = vw_x * mag; |
488 | REAL y = vw_y * mag; |
489 | REAL z = vw_z * mag; |
490 | |
491 | |
492 | REAL D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2])); |
493 | |
494 | n[0] = x; |
495 | n[1] = y; |
496 | n[2] = z; |
497 | |
498 | return D; |
499 | } |
500 | |
501 | REAL fm_distToPlane(const REAL *plane,const REAL *p) // computes the distance of this point from the plane. |
502 | { |
503 | return p[0]*plane[0]+p[1]*plane[1]+p[2]*plane[2]+plane[3]; |
504 | } |
505 | |
506 | REAL fm_dot(const REAL *p1,const REAL *p2) |
507 | { |
508 | return p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]; |
509 | } |
510 | |
511 | void fm_cross(REAL *cross,const REAL *a,const REAL *b) |
512 | { |
513 | cross[0] = a[1]*b[2] - a[2]*b[1]; |
514 | cross[1] = a[2]*b[0] - a[0]*b[2]; |
515 | cross[2] = a[0]*b[1] - a[1]*b[0]; |
516 | } |
517 | |
518 | REAL fm_computeNormalVector(REAL *n,const REAL *p1,const REAL *p2) |
519 | { |
520 | n[0] = p2[0] - p1[0]; |
521 | n[1] = p2[1] - p1[1]; |
522 | n[2] = p2[2] - p1[2]; |
523 | return fm_normalize(n); |
524 | } |
525 | |
526 | bool fm_computeWindingOrder(const REAL *p1,const REAL *p2,const REAL *p3) // returns true if the triangle is clockwise. |
527 | { |
528 | bool ret = false; |
529 | |
530 | REAL v1[3]; |
531 | REAL v2[3]; |
532 | |
533 | fm_computeNormalVector(v1,p1,p2); // p2-p1 (as vector) and then normalized |
534 | fm_computeNormalVector(v2,p1,p3); // p3-p1 (as vector) and then normalized |
535 | |
536 | REAL cross[3]; |
537 | |
538 | fm_cross(cross, v1, v2 ); |
539 | REAL ref[3] = { 1, 0, 0 }; |
540 | |
541 | REAL d = fm_dot( cross, ref ); |
542 | |
543 | |
544 | if ( d <= 0 ) |
545 | ret = false; |
546 | else |
547 | ret = true; |
548 | |
549 | return ret; |
550 | } |
551 | |
552 | REAL fm_normalize(REAL *n) // normalize this vector |
553 | { |
554 | REAL dist = (REAL)sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); |
555 | if ( dist > 0.0000001f ) |
556 | { |
557 | REAL mag = 1.0f / dist; |
558 | n[0]*=mag; |
559 | n[1]*=mag; |
560 | n[2]*=mag; |
561 | } |
562 | else |
563 | { |
564 | n[0] = 1; |
565 | n[1] = 0; |
566 | n[2] = 0; |
567 | } |
568 | |
569 | return dist; |
570 | } |
571 | |
572 | |
573 | void fm_matrixMultiply(const REAL *pA,const REAL *pB,REAL *pM) |
574 | { |
575 | #if 1 |
576 | |
577 | REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; |
578 | REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; |
579 | REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; |
580 | REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; |
581 | |
582 | REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; |
583 | REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; |
584 | REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; |
585 | REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; |
586 | |
587 | REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; |
588 | REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; |
589 | REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; |
590 | REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; |
591 | |
592 | REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; |
593 | REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; |
594 | REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; |
595 | REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; |
596 | |
597 | pM[0] = a; |
598 | pM[1] = b; |
599 | pM[2] = c; |
600 | pM[3] = d; |
601 | |
602 | pM[4] = e; |
603 | pM[5] = f; |
604 | pM[6] = g; |
605 | pM[7] = h; |
606 | |
607 | pM[8] = i; |
608 | pM[9] = j; |
609 | pM[10] = k; |
610 | pM[11] = l; |
611 | |
612 | pM[12] = m; |
613 | pM[13] = n; |
614 | pM[14] = o; |
615 | pM[15] = p; |
616 | |
617 | |
618 | #else |
619 | memset(pM, 0, sizeof(REAL)*16); |
620 | for(int32_t i=0; i<4; i++ ) |
621 | for(int32_t j=0; j<4; j++ ) |
622 | for(int32_t k=0; k<4; k++ ) |
623 | pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; |
624 | #endif |
625 | } |
626 | |
627 | |
628 | void fm_eulerToQuatDX(REAL x,REAL y,REAL z,REAL *quat) // convert euler angles to quaternion using the fucked up DirectX method |
629 | { |
630 | REAL matrix[16]; |
631 | fm_eulerToMatrix(x,y,z,matrix); |
632 | fm_matrixToQuat(matrix,quat); |
633 | } |
634 | |
635 | // implementation copied from: http://blogs.msdn.com/mikepelton/archive/2004/10/29/249501.aspx |
636 | void fm_eulerToMatrixDX(REAL x,REAL y,REAL z,REAL *matrix) // convert euler angles to quaternion using the fucked up DirectX method. |
637 | { |
638 | fm_identity(matrix); |
639 | matrix[0*4+0] = (REAL)(cos(z)*cos(y) + sin(z)*sin(x)*sin(y)); |
640 | matrix[0*4+1] = (REAL)(sin(z)*cos(x)); |
641 | matrix[0*4+2] = (REAL)(cos(z)*-sin(y) + sin(z)*sin(x)*cos(y)); |
642 | |
643 | matrix[1*4+0] = (REAL)(-sin(z)*cos(y)+cos(z)*sin(x)*sin(y)); |
644 | matrix[1*4+1] = (REAL)(cos(z)*cos(x)); |
645 | matrix[1*4+2] = (REAL)(sin(z)*sin(y) +cos(z)*sin(x)*cos(y)); |
646 | |
647 | matrix[2*4+0] = (REAL)(cos(x)*sin(y)); |
648 | matrix[2*4+1] = (REAL)(-sin(x)); |
649 | matrix[2*4+2] = (REAL)(cos(x)*cos(y)); |
650 | } |
651 | |
652 | |
653 | void fm_scale(REAL x,REAL y,REAL z,REAL *fscale) // apply scale to the matrix. |
654 | { |
655 | fscale[0*4+0] = x; |
656 | fscale[1*4+1] = y; |
657 | fscale[2*4+2] = z; |
658 | } |
659 | |
660 | |
661 | void fm_composeTransform(const REAL *position,const REAL *quat,const REAL *scale,REAL *matrix) |
662 | { |
663 | fm_identity(matrix); |
664 | fm_quatToMatrix(quat,matrix); |
665 | |
666 | if ( scale && ( scale[0] != 1 || scale[1] != 1 || scale[2] != 1 ) ) |
667 | { |
668 | REAL work[16]; |
669 | memcpy(work,matrix,sizeof(REAL)*16); |
670 | REAL mscale[16]; |
671 | fm_identity(mscale); |
672 | fm_scale(scale[0],scale[1],scale[2],mscale); |
673 | fm_matrixMultiply(work,mscale,matrix); |
674 | } |
675 | |
676 | matrix[12] = position[0]; |
677 | matrix[13] = position[1]; |
678 | matrix[14] = position[2]; |
679 | } |
680 | |
681 | |
682 | void fm_setTranslation(const REAL *translation,REAL *matrix) |
683 | { |
684 | matrix[12] = translation[0]; |
685 | matrix[13] = translation[1]; |
686 | matrix[14] = translation[2]; |
687 | } |
688 | |
689 | static REAL enorm0_3d ( REAL x0, REAL y0, REAL z0, REAL x1, REAL y1, REAL z1 ) |
690 | |
691 | /**********************************************************************/ |
692 | |
693 | /* |
694 | Purpose: |
695 | |
696 | ENORM0_3D computes the Euclidean norm of (P1-P0) in 3D. |
697 | |
698 | Modified: |
699 | |
700 | 18 April 1999 |
701 | |
702 | Author: |
703 | |
704 | John Burkardt |
705 | |
706 | Parameters: |
707 | |
708 | Input, REAL X0, Y0, Z0, X1, Y1, Z1, the coordinates of the points |
709 | P0 and P1. |
710 | |
711 | Output, REAL ENORM0_3D, the Euclidean norm of (P1-P0). |
712 | */ |
713 | { |
714 | REAL value; |
715 | |
716 | value = (REAL)sqrt ( |
717 | ( x1 - x0 ) * ( x1 - x0 ) + |
718 | ( y1 - y0 ) * ( y1 - y0 ) + |
719 | ( z1 - z0 ) * ( z1 - z0 ) ); |
720 | |
721 | return value; |
722 | } |
723 | |
724 | |
725 | static REAL triangle_area_3d ( REAL x1, REAL y1, REAL z1, REAL x2,REAL y2, REAL z2, REAL x3, REAL y3, REAL z3 ) |
726 | |
727 | /**********************************************************************/ |
728 | |
729 | /* |
730 | Purpose: |
731 | |
732 | TRIANGLE_AREA_3D computes the area of a triangle in 3D. |
733 | |
734 | Modified: |
735 | |
736 | 22 April 1999 |
737 | |
738 | Author: |
739 | |
740 | John Burkardt |
741 | |
742 | Parameters: |
743 | |
744 | Input, REAL X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, the (X,Y,Z) |
745 | coordinates of the corners of the triangle. |
746 | |
747 | Output, REAL TRIANGLE_AREA_3D, the area of the triangle. |
748 | */ |
749 | { |
750 | REAL a; |
751 | REAL alpha; |
752 | REAL area; |
753 | REAL b; |
754 | REAL base; |
755 | REAL c; |
756 | REAL dot; |
757 | REAL height; |
758 | /* |
759 | Find the projection of (P3-P1) onto (P2-P1). |
760 | */ |
761 | dot = |
762 | ( x2 - x1 ) * ( x3 - x1 ) + |
763 | ( y2 - y1 ) * ( y3 - y1 ) + |
764 | ( z2 - z1 ) * ( z3 - z1 ); |
765 | |
766 | base = enorm0_3d ( x1, y1, z1, x2, y2, z2 ); |
767 | /* |
768 | The height of the triangle is the length of (P3-P1) after its |
769 | projection onto (P2-P1) has been subtracted. |
770 | */ |
771 | if ( base == 0.0 ) { |
772 | |
773 | height = 0.0; |
774 | |
775 | } |
776 | else { |
777 | |
778 | alpha = dot / ( base * base ); |
779 | |
780 | a = x3 - x1 - alpha * ( x2 - x1 ); |
781 | b = y3 - y1 - alpha * ( y2 - y1 ); |
782 | c = z3 - z1 - alpha * ( z2 - z1 ); |
783 | |
784 | height = (REAL)sqrt ( a * a + b * b + c * c ); |
785 | |
786 | } |
787 | |
788 | area = 0.5f * base * height; |
789 | |
790 | return area; |
791 | } |
792 | |
793 | |
794 | REAL fm_computeArea(const REAL *p1,const REAL *p2,const REAL *p3) |
795 | { |
796 | REAL ret = 0; |
797 | |
798 | ret = triangle_area_3d(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]); |
799 | |
800 | return ret; |
801 | } |
802 | |
803 | |
804 | void fm_lerp(const REAL *p1,const REAL *p2,REAL *dest,REAL lerpValue) |
805 | { |
806 | dest[0] = ((p2[0] - p1[0])*lerpValue) + p1[0]; |
807 | dest[1] = ((p2[1] - p1[1])*lerpValue) + p1[1]; |
808 | dest[2] = ((p2[2] - p1[2])*lerpValue) + p1[2]; |
809 | } |
810 | |
811 | bool fm_pointTestXZ(const REAL *p,const REAL *i,const REAL *j) |
812 | { |
813 | bool ret = false; |
814 | |
815 | if (((( i[2] <= p[2] ) && ( p[2] < j[2] )) || (( j[2] <= p[2] ) && ( p[2] < i[2] ))) && ( p[0] < (j[0] - i[0]) * (p[2] - i[2]) / (j[2] - i[2]) + i[0])) |
816 | ret = true; |
817 | |
818 | return ret; |
819 | }; |
820 | |
821 | |
822 | bool fm_insideTriangleXZ(const REAL *p,const REAL *p1,const REAL *p2,const REAL *p3) |
823 | { |
824 | bool ret = false; |
825 | |
826 | int32_t c = 0; |
827 | if ( fm_pointTestXZ(p,p1,p2) ) c = !c; |
828 | if ( fm_pointTestXZ(p,p2,p3) ) c = !c; |
829 | if ( fm_pointTestXZ(p,p3,p1) ) c = !c; |
830 | if ( c ) ret = true; |
831 | |
832 | return ret; |
833 | } |
834 | |
835 | bool fm_insideAABB(const REAL *pos,const REAL *bmin,const REAL *bmax) |
836 | { |
837 | bool ret = false; |
838 | |
839 | if ( pos[0] >= bmin[0] && pos[0] <= bmax[0] && |
840 | pos[1] >= bmin[1] && pos[1] <= bmax[1] && |
841 | pos[2] >= bmin[2] && pos[2] <= bmax[2] ) |
842 | ret = true; |
843 | |
844 | return ret; |
845 | } |
846 | |
847 | |
848 | uint32_t fm_clipTestPoint(const REAL *bmin,const REAL *bmax,const REAL *pos) |
849 | { |
850 | uint32_t ret = 0; |
851 | |
852 | if ( pos[0] < bmin[0] ) |
853 | ret|=FMCS_XMIN; |
854 | else if ( pos[0] > bmax[0] ) |
855 | ret|=FMCS_XMAX; |
856 | |
857 | if ( pos[1] < bmin[1] ) |
858 | ret|=FMCS_YMIN; |
859 | else if ( pos[1] > bmax[1] ) |
860 | ret|=FMCS_YMAX; |
861 | |
862 | if ( pos[2] < bmin[2] ) |
863 | ret|=FMCS_ZMIN; |
864 | else if ( pos[2] > bmax[2] ) |
865 | ret|=FMCS_ZMAX; |
866 | |
867 | return ret; |
868 | } |
869 | |
870 | uint32_t fm_clipTestPointXZ(const REAL *bmin,const REAL *bmax,const REAL *pos) // only tests X and Z, not Y |
871 | { |
872 | uint32_t ret = 0; |
873 | |
874 | if ( pos[0] < bmin[0] ) |
875 | ret|=FMCS_XMIN; |
876 | else if ( pos[0] > bmax[0] ) |
877 | ret|=FMCS_XMAX; |
878 | |
879 | if ( pos[2] < bmin[2] ) |
880 | ret|=FMCS_ZMIN; |
881 | else if ( pos[2] > bmax[2] ) |
882 | ret|=FMCS_ZMAX; |
883 | |
884 | return ret; |
885 | } |
886 | |
887 | uint32_t fm_clipTestAABB(const REAL *bmin,const REAL *bmax,const REAL *p1,const REAL *p2,const REAL *p3,uint32_t &andCode) |
888 | { |
889 | uint32_t orCode = 0; |
890 | |
891 | andCode = FMCS_XMIN | FMCS_XMAX | FMCS_YMIN | FMCS_YMAX | FMCS_ZMIN | FMCS_ZMAX; |
892 | |
893 | uint32_t c = fm_clipTestPoint(bmin,bmax,p1); |
894 | orCode|=c; |
895 | andCode&=c; |
896 | |
897 | c = fm_clipTestPoint(bmin,bmax,p2); |
898 | orCode|=c; |
899 | andCode&=c; |
900 | |
901 | c = fm_clipTestPoint(bmin,bmax,p3); |
902 | orCode|=c; |
903 | andCode&=c; |
904 | |
905 | return orCode; |
906 | } |
907 | |
908 | bool intersect(const REAL *si,const REAL *ei,const REAL *bmin,const REAL *bmax,REAL *time) |
909 | { |
910 | REAL st,et,fst = 0,fet = 1; |
911 | |
912 | for (int32_t i = 0; i < 3; i++) |
913 | { |
914 | if (*si < *ei) |
915 | { |
916 | if (*si > *bmax || *ei < *bmin) |
917 | return false; |
918 | REAL di = *ei - *si; |
919 | st = (*si < *bmin)? (*bmin - *si) / di: 0; |
920 | et = (*ei > *bmax)? (*bmax - *si) / di: 1; |
921 | } |
922 | else |
923 | { |
924 | if (*ei > *bmax || *si < *bmin) |
925 | return false; |
926 | REAL di = *ei - *si; |
927 | st = (*si > *bmax)? (*bmax - *si) / di: 0; |
928 | et = (*ei < *bmin)? (*bmin - *si) / di: 1; |
929 | } |
930 | |
931 | if (st > fst) fst = st; |
932 | if (et < fet) fet = et; |
933 | if (fet < fst) |
934 | return false; |
935 | bmin++; bmax++; |
936 | si++; ei++; |
937 | } |
938 | |
939 | *time = fst; |
940 | return true; |
941 | } |
942 | |
943 | |
944 | |
945 | bool fm_lineTestAABB(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) |
946 | { |
947 | bool sect = intersect(p1,p2,bmin,bmax,&time); |
948 | return sect; |
949 | } |
950 | |
951 | |
952 | bool fm_lineTestAABBXZ(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) |
953 | { |
954 | REAL _bmin[3]; |
955 | REAL _bmax[3]; |
956 | |
957 | _bmin[0] = bmin[0]; |
958 | _bmin[1] = -1e9; |
959 | _bmin[2] = bmin[2]; |
960 | |
961 | _bmax[0] = bmax[0]; |
962 | _bmax[1] = 1e9; |
963 | _bmax[2] = bmax[2]; |
964 | |
965 | bool sect = intersect(p1,p2,_bmin,_bmax,&time); |
966 | |
967 | return sect; |
968 | } |
969 | |
970 | void fm_minmax(const REAL *p,REAL *bmin,REAL *bmax) // accmulate to a min-max value |
971 | { |
972 | |
973 | if ( p[0] < bmin[0] ) bmin[0] = p[0]; |
974 | if ( p[1] < bmin[1] ) bmin[1] = p[1]; |
975 | if ( p[2] < bmin[2] ) bmin[2] = p[2]; |
976 | |
977 | if ( p[0] > bmax[0] ) bmax[0] = p[0]; |
978 | if ( p[1] > bmax[1] ) bmax[1] = p[1]; |
979 | if ( p[2] > bmax[2] ) bmax[2] = p[2]; |
980 | |
981 | } |
982 | |
983 | REAL fm_solveX(const REAL *plane,REAL y,REAL z) // solve for X given this plane equation and the other two components. |
984 | { |
985 | REAL x = (y*plane[1]+z*plane[2]+plane[3]) / -plane[0]; |
986 | return x; |
987 | } |
988 | |
989 | REAL fm_solveY(const REAL *plane,REAL x,REAL z) // solve for Y given this plane equation and the other two components. |
990 | { |
991 | REAL y = (x*plane[0]+z*plane[2]+plane[3]) / -plane[1]; |
992 | return y; |
993 | } |
994 | |
995 | |
996 | REAL fm_solveZ(const REAL *plane,REAL x,REAL y) // solve for Y given this plane equation and the other two components. |
997 | { |
998 | REAL z = (x*plane[0]+y*plane[1]+plane[3]) / -plane[2]; |
999 | return z; |
1000 | } |
1001 | |
1002 | |
1003 | void fm_getAABBCenter(const REAL *bmin,const REAL *bmax,REAL *center) |
1004 | { |
1005 | center[0] = (bmax[0]-bmin[0])*0.5f+bmin[0]; |
1006 | center[1] = (bmax[1]-bmin[1])*0.5f+bmin[1]; |
1007 | center[2] = (bmax[2]-bmin[2])*0.5f+bmin[2]; |
1008 | } |
1009 | |
1010 | FM_Axis fm_getDominantAxis(const REAL normal[3]) |
1011 | { |
1012 | FM_Axis ret = FM_XAXIS; |
1013 | |
1014 | REAL x = (REAL)fabs(normal[0]); |
1015 | REAL y = (REAL)fabs(normal[1]); |
1016 | REAL z = (REAL)fabs(normal[2]); |
1017 | |
1018 | if ( y > x && y > z ) |
1019 | ret = FM_YAXIS; |
1020 | else if ( z > x && z > y ) |
1021 | ret = FM_ZAXIS; |
1022 | |
1023 | return ret; |
1024 | } |
1025 | |
1026 | |
1027 | bool fm_lineSphereIntersect(const REAL *center,REAL radius,const REAL *p1,const REAL *p2,REAL *intersect) |
1028 | { |
1029 | bool ret = false; |
1030 | |
1031 | REAL dir[3]; |
1032 | |
1033 | dir[0] = p2[0]-p1[0]; |
1034 | dir[1] = p2[1]-p1[1]; |
1035 | dir[2] = p2[2]-p1[2]; |
1036 | |
1037 | REAL distance = (REAL)sqrt( dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]); |
1038 | |
1039 | if ( distance > 0 ) |
1040 | { |
1041 | REAL recip = 1.0f / distance; |
1042 | dir[0]*=recip; |
1043 | dir[1]*=recip; |
1044 | dir[2]*=recip; |
1045 | ret = fm_raySphereIntersect(center,radius,p1,dir,distance,intersect); |
1046 | } |
1047 | else |
1048 | { |
1049 | dir[0] = center[0]-p1[0]; |
1050 | dir[1] = center[1]-p1[1]; |
1051 | dir[2] = center[2]-p1[2]; |
1052 | REAL d2 = dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]; |
1053 | REAL r2 = radius*radius; |
1054 | if ( d2 < r2 ) |
1055 | { |
1056 | ret = true; |
1057 | if ( intersect ) |
1058 | { |
1059 | intersect[0] = p1[0]; |
1060 | intersect[1] = p1[1]; |
1061 | intersect[2] = p1[2]; |
1062 | } |
1063 | } |
1064 | } |
1065 | return ret; |
1066 | } |
1067 | |
1068 | #define DOT(p1,p2) (p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]) |
1069 | |
1070 | bool fm_raySphereIntersect(const REAL *center,REAL radius,const REAL *pos,const REAL *dir,REAL distance,REAL *intersect) |
1071 | { |
1072 | bool ret = false; |
1073 | |
1074 | REAL E0[3]; |
1075 | |
1076 | E0[0] = center[0] - pos[0]; |
1077 | E0[1] = center[1] - pos[1]; |
1078 | E0[2] = center[2] - pos[2]; |
1079 | |
1080 | REAL V[3]; |
1081 | |
1082 | V[0] = dir[0]; |
1083 | V[1] = dir[1]; |
1084 | V[2] = dir[2]; |
1085 | |
1086 | |
1087 | REAL dist2 = E0[0]*E0[0] + E0[1]*E0[1] + E0[2] * E0[2]; |
1088 | REAL radius2 = radius*radius; // radius squared.. |
1089 | |
1090 | // Bug Fix For Gem, if origin is *inside* the sphere, invert the |
1091 | // direction vector so that we get a valid intersection location. |
1092 | if ( dist2 < radius2 ) |
1093 | { |
1094 | V[0]*=-1; |
1095 | V[1]*=-1; |
1096 | V[2]*=-1; |
1097 | } |
1098 | |
1099 | |
1100 | REAL v = DOT(E0,V); |
1101 | |
1102 | REAL disc = radius2 - (dist2 - v*v); |
1103 | |
1104 | if (disc > 0.0f) |
1105 | { |
1106 | if ( intersect ) |
1107 | { |
1108 | REAL d = (REAL)sqrt(disc); |
1109 | REAL diff = v-d; |
1110 | if ( diff < distance ) |
1111 | { |
1112 | intersect[0] = pos[0]+V[0]*diff; |
1113 | intersect[1] = pos[1]+V[1]*diff; |
1114 | intersect[2] = pos[2]+V[2]*diff; |
1115 | ret = true; |
1116 | } |
1117 | } |
1118 | } |
1119 | |
1120 | return ret; |
1121 | } |
1122 | |
1123 | |
1124 | void fm_catmullRom(REAL *out_vector,const REAL *p1,const REAL *p2,const REAL *p3,const REAL *p4, const REAL s) |
1125 | { |
1126 | REAL s_squared = s * s; |
1127 | REAL s_cubed = s_squared * s; |
1128 | |
1129 | REAL coefficient_p1 = -s_cubed + 2*s_squared - s; |
1130 | REAL coefficient_p2 = 3 * s_cubed - 5 * s_squared + 2; |
1131 | REAL coefficient_p3 = -3 * s_cubed +4 * s_squared + s; |
1132 | REAL coefficient_p4 = s_cubed - s_squared; |
1133 | |
1134 | out_vector[0] = (coefficient_p1 * p1[0] + coefficient_p2 * p2[0] + coefficient_p3 * p3[0] + coefficient_p4 * p4[0])*0.5f; |
1135 | out_vector[1] = (coefficient_p1 * p1[1] + coefficient_p2 * p2[1] + coefficient_p3 * p3[1] + coefficient_p4 * p4[1])*0.5f; |
1136 | out_vector[2] = (coefficient_p1 * p1[2] + coefficient_p2 * p2[2] + coefficient_p3 * p3[2] + coefficient_p4 * p4[2])*0.5f; |
1137 | } |
1138 | |
1139 | bool fm_intersectAABB(const REAL *bmin1,const REAL *bmax1,const REAL *bmin2,const REAL *bmax2) |
1140 | { |
1141 | if ((bmin1[0] > bmax2[0]) || (bmin2[0] > bmax1[0])) return false; |
1142 | if ((bmin1[1] > bmax2[1]) || (bmin2[1] > bmax1[1])) return false; |
1143 | if ((bmin1[2] > bmax2[2]) || (bmin2[2] > bmax1[2])) return false; |
1144 | return true; |
1145 | |
1146 | } |
1147 | |
1148 | bool fm_insideAABB(const REAL *obmin,const REAL *obmax,const REAL *tbmin,const REAL *tbmax) // test if bounding box tbmin/tmbax is fully inside obmin/obmax |
1149 | { |
1150 | bool ret = false; |
1151 | |
1152 | if ( tbmax[0] <= obmax[0] && |
1153 | tbmax[1] <= obmax[1] && |
1154 | tbmax[2] <= obmax[2] && |
1155 | tbmin[0] >= obmin[0] && |
1156 | tbmin[1] >= obmin[1] && |
1157 | tbmin[2] >= obmin[2] ) ret = true; |
1158 | |
1159 | return ret; |
1160 | } |
1161 | |
1162 | |
1163 | // Reference, from Stan Melax in Game Gems I |
1164 | // Quaternion q; |
1165 | // vector3 c = CrossProduct(v0,v1); |
1166 | // REAL d = DotProduct(v0,v1); |
1167 | // REAL s = (REAL)sqrt((1+d)*2); |
1168 | // q.x = c.x / s; |
1169 | // q.y = c.y / s; |
1170 | // q.z = c.z / s; |
1171 | // q.w = s /2.0f; |
1172 | // return q; |
1173 | void fm_rotationArc(const REAL *v0,const REAL *v1,REAL *quat) |
1174 | { |
1175 | REAL cross[3]; |
1176 | |
1177 | fm_cross(cross,v0,v1); |
1178 | REAL d = fm_dot(v0,v1); |
1179 | |
1180 | if( d<= -0.99999f ) // 180 about x axis |
1181 | { |
1182 | if ( fabsf((float)v0[0]) < 0.1f ) |
1183 | { |
1184 | quat[0] = 0; |
1185 | quat[1] = v0[2]; |
1186 | quat[2] = -v0[1]; |
1187 | quat[3] = 0; |
1188 | } |
1189 | else |
1190 | { |
1191 | quat[0] = v0[1]; |
1192 | quat[1] = -v0[0]; |
1193 | quat[2] = 0; |
1194 | quat[3] = 0; |
1195 | } |
1196 | REAL magnitudeSquared = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2] + quat[3]*quat[3]; |
1197 | REAL magnitude = sqrtf((float)magnitudeSquared); |
1198 | REAL recip = 1.0f / magnitude; |
1199 | quat[0]*=recip; |
1200 | quat[1]*=recip; |
1201 | quat[2]*=recip; |
1202 | quat[3]*=recip; |
1203 | } |
1204 | else |
1205 | { |
1206 | REAL s = (REAL)sqrt((1+d)*2); |
1207 | REAL recip = 1.0f / s; |
1208 | |
1209 | quat[0] = cross[0] * recip; |
1210 | quat[1] = cross[1] * recip; |
1211 | quat[2] = cross[2] * recip; |
1212 | quat[3] = s * 0.5f; |
1213 | } |
1214 | } |
1215 | |
1216 | |
1217 | REAL fm_distancePointLineSegment(const REAL *Point,const REAL *LineStart,const REAL *LineEnd,REAL *intersection,LineSegmentType &type,REAL epsilon) |
1218 | { |
1219 | REAL ret; |
1220 | |
1221 | REAL LineMag = fm_distance( LineEnd, LineStart ); |
1222 | |
1223 | if ( LineMag > 0 ) |
1224 | { |
1225 | REAL U = ( ( ( Point[0] - LineStart[0] ) * ( LineEnd[0] - LineStart[0] ) ) + ( ( Point[1] - LineStart[1] ) * ( LineEnd[1] - LineStart[1] ) ) + ( ( Point[2] - LineStart[2] ) * ( LineEnd[2] - LineStart[2] ) ) ) / ( LineMag * LineMag ); |
1226 | if( U < 0.0f || U > 1.0f ) |
1227 | { |
1228 | REAL d1 = fm_distanceSquared(Point,LineStart); |
1229 | REAL d2 = fm_distanceSquared(Point,LineEnd); |
1230 | if ( d1 <= d2 ) |
1231 | { |
1232 | ret = (REAL)sqrt(d1); |
1233 | intersection[0] = LineStart[0]; |
1234 | intersection[1] = LineStart[1]; |
1235 | intersection[2] = LineStart[2]; |
1236 | type = LS_START; |
1237 | } |
1238 | else |
1239 | { |
1240 | ret = (REAL)sqrt(d2); |
1241 | intersection[0] = LineEnd[0]; |
1242 | intersection[1] = LineEnd[1]; |
1243 | intersection[2] = LineEnd[2]; |
1244 | type = LS_END; |
1245 | } |
1246 | } |
1247 | else |
1248 | { |
1249 | intersection[0] = LineStart[0] + U * ( LineEnd[0] - LineStart[0] ); |
1250 | intersection[1] = LineStart[1] + U * ( LineEnd[1] - LineStart[1] ); |
1251 | intersection[2] = LineStart[2] + U * ( LineEnd[2] - LineStart[2] ); |
1252 | |
1253 | ret = fm_distance(Point,intersection); |
1254 | |
1255 | REAL d1 = fm_distanceSquared(intersection,LineStart); |
1256 | REAL d2 = fm_distanceSquared(intersection,LineEnd); |
1257 | REAL mag = (epsilon*2)*(epsilon*2); |
1258 | |
1259 | if ( d1 < mag ) // if less than 1/100th the total distance, treat is as the 'start' |
1260 | { |
1261 | type = LS_START; |
1262 | } |
1263 | else if ( d2 < mag ) |
1264 | { |
1265 | type = LS_END; |
1266 | } |
1267 | else |
1268 | { |
1269 | type = LS_MIDDLE; |
1270 | } |
1271 | |
1272 | } |
1273 | } |
1274 | else |
1275 | { |
1276 | ret = LineMag; |
1277 | intersection[0] = LineEnd[0]; |
1278 | intersection[1] = LineEnd[1]; |
1279 | intersection[2] = LineEnd[2]; |
1280 | type = LS_END; |
1281 | } |
1282 | |
1283 | return ret; |
1284 | } |
1285 | |
1286 | |
1287 | #ifndef BEST_FIT_PLANE_H |
1288 | |
1289 | #define BEST_FIT_PLANE_H |
1290 | |
1291 | template <class Type> class Eigen |
1292 | { |
1293 | public: |
1294 | |
1295 | |
1296 | void DecrSortEigenStuff(void) |
1297 | { |
1298 | Tridiagonal(); //diagonalize the matrix. |
1299 | QLAlgorithm(); // |
1300 | DecreasingSort(); |
1301 | GuaranteeRotation(); |
1302 | } |
1303 | |
1304 | void Tridiagonal(void) |
1305 | { |
1306 | Type fM00 = mElement[0][0]; |
1307 | Type fM01 = mElement[0][1]; |
1308 | Type fM02 = mElement[0][2]; |
1309 | Type fM11 = mElement[1][1]; |
1310 | Type fM12 = mElement[1][2]; |
1311 | Type fM22 = mElement[2][2]; |
1312 | |
1313 | m_afDiag[0] = fM00; |
1314 | m_afSubd[2] = 0; |
1315 | if (fM02 != (Type)0.0) |
1316 | { |
1317 | Type fLength = (REAL)sqrt(fM01*fM01+fM02*fM02); |
1318 | Type fInvLength = ((Type)1.0)/fLength; |
1319 | fM01 *= fInvLength; |
1320 | fM02 *= fInvLength; |
1321 | Type fQ = ((Type)2.0)*fM01*fM12+fM02*(fM22-fM11); |
1322 | m_afDiag[1] = fM11+fM02*fQ; |
1323 | m_afDiag[2] = fM22-fM02*fQ; |
1324 | m_afSubd[0] = fLength; |
1325 | m_afSubd[1] = fM12-fM01*fQ; |
1326 | mElement[0][0] = (Type)1.0; |
1327 | mElement[0][1] = (Type)0.0; |
1328 | mElement[0][2] = (Type)0.0; |
1329 | mElement[1][0] = (Type)0.0; |
1330 | mElement[1][1] = fM01; |
1331 | mElement[1][2] = fM02; |
1332 | mElement[2][0] = (Type)0.0; |
1333 | mElement[2][1] = fM02; |
1334 | mElement[2][2] = -fM01; |
1335 | m_bIsRotation = false; |
1336 | } |
1337 | else |
1338 | { |
1339 | m_afDiag[1] = fM11; |
1340 | m_afDiag[2] = fM22; |
1341 | m_afSubd[0] = fM01; |
1342 | m_afSubd[1] = fM12; |
1343 | mElement[0][0] = (Type)1.0; |
1344 | mElement[0][1] = (Type)0.0; |
1345 | mElement[0][2] = (Type)0.0; |
1346 | mElement[1][0] = (Type)0.0; |
1347 | mElement[1][1] = (Type)1.0; |
1348 | mElement[1][2] = (Type)0.0; |
1349 | mElement[2][0] = (Type)0.0; |
1350 | mElement[2][1] = (Type)0.0; |
1351 | mElement[2][2] = (Type)1.0; |
1352 | m_bIsRotation = true; |
1353 | } |
1354 | } |
1355 | |
1356 | bool QLAlgorithm(void) |
1357 | { |
1358 | const int32_t iMaxIter = 32; |
1359 | |
1360 | for (int32_t i0 = 0; i0 <3; i0++) |
1361 | { |
1362 | int32_t i1; |
1363 | for (i1 = 0; i1 < iMaxIter; i1++) |
1364 | { |
1365 | int32_t i2; |
1366 | for (i2 = i0; i2 <= (3-2); i2++) |
1367 | { |
1368 | Type fTmp = fabs(m_afDiag[i2]) + fabs(m_afDiag[i2+1]); |
1369 | if ( fabs(m_afSubd[i2]) + fTmp == fTmp ) |
1370 | break; |
1371 | } |
1372 | if (i2 == i0) |
1373 | { |
1374 | break; |
1375 | } |
1376 | |
1377 | Type fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((Type)2.0) * m_afSubd[i0]); |
1378 | Type fR = (REAL)sqrt(fG*fG+(Type)1.0); |
1379 | if (fG < (Type)0.0) |
1380 | { |
1381 | fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR); |
1382 | } |
1383 | else |
1384 | { |
1385 | fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR); |
1386 | } |
1387 | Type fSin = (Type)1.0, fCos = (Type)1.0, fP = (Type)0.0; |
1388 | for (int32_t i3 = i2-1; i3 >= i0; i3--) |
1389 | { |
1390 | Type fF = fSin*m_afSubd[i3]; |
1391 | Type fB = fCos*m_afSubd[i3]; |
1392 | if (fabs(fF) >= fabs(fG)) |
1393 | { |
1394 | fCos = fG/fF; |
1395 | fR = (REAL)sqrt(fCos*fCos+(Type)1.0); |
1396 | m_afSubd[i3+1] = fF*fR; |
1397 | fSin = ((Type)1.0)/fR; |
1398 | fCos *= fSin; |
1399 | } |
1400 | else |
1401 | { |
1402 | fSin = fF/fG; |
1403 | fR = (REAL)sqrt(fSin*fSin+(Type)1.0); |
1404 | m_afSubd[i3+1] = fG*fR; |
1405 | fCos = ((Type)1.0)/fR; |
1406 | fSin *= fCos; |
1407 | } |
1408 | fG = m_afDiag[i3+1]-fP; |
1409 | fR = (m_afDiag[i3]-fG)*fSin+((Type)2.0)*fB*fCos; |
1410 | fP = fSin*fR; |
1411 | m_afDiag[i3+1] = fG+fP; |
1412 | fG = fCos*fR-fB; |
1413 | for (int32_t i4 = 0; i4 < 3; i4++) |
1414 | { |
1415 | fF = mElement[i4][i3+1]; |
1416 | mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF; |
1417 | mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF; |
1418 | } |
1419 | } |
1420 | m_afDiag[i0] -= fP; |
1421 | m_afSubd[i0] = fG; |
1422 | m_afSubd[i2] = (Type)0.0; |
1423 | } |
1424 | if (i1 == iMaxIter) |
1425 | { |
1426 | return false; |
1427 | } |
1428 | } |
1429 | return true; |
1430 | } |
1431 | |
1432 | void DecreasingSort(void) |
1433 | { |
1434 | //sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1] |
1435 | for (int32_t i0 = 0, i1; i0 <= 3-2; i0++) |
1436 | { |
1437 | // locate maximum eigenvalue |
1438 | i1 = i0; |
1439 | Type fMax = m_afDiag[i1]; |
1440 | int32_t i2; |
1441 | for (i2 = i0+1; i2 < 3; i2++) |
1442 | { |
1443 | if (m_afDiag[i2] > fMax) |
1444 | { |
1445 | i1 = i2; |
1446 | fMax = m_afDiag[i1]; |
1447 | } |
1448 | } |
1449 | |
1450 | if (i1 != i0) |
1451 | { |
1452 | // swap eigenvalues |
1453 | m_afDiag[i1] = m_afDiag[i0]; |
1454 | m_afDiag[i0] = fMax; |
1455 | // swap eigenvectors |
1456 | for (i2 = 0; i2 < 3; i2++) |
1457 | { |
1458 | Type fTmp = mElement[i2][i0]; |
1459 | mElement[i2][i0] = mElement[i2][i1]; |
1460 | mElement[i2][i1] = fTmp; |
1461 | m_bIsRotation = !m_bIsRotation; |
1462 | } |
1463 | } |
1464 | } |
1465 | } |
1466 | |
1467 | |
1468 | void GuaranteeRotation(void) |
1469 | { |
1470 | if (!m_bIsRotation) |
1471 | { |
1472 | // change sign on the first column |
1473 | for (int32_t iRow = 0; iRow <3; iRow++) |
1474 | { |
1475 | mElement[iRow][0] = -mElement[iRow][0]; |
1476 | } |
1477 | } |
1478 | } |
1479 | |
1480 | Type mElement[3][3]; |
1481 | Type m_afDiag[3]; |
1482 | Type m_afSubd[3]; |
1483 | bool m_bIsRotation; |
1484 | }; |
1485 | |
1486 | #endif |
1487 | |
1488 | bool fm_computeBestFitPlane(uint32_t vcount, |
1489 | const REAL *points, |
1490 | uint32_t vstride, |
1491 | const REAL *weights, |
1492 | uint32_t wstride, |
1493 | REAL *plane, |
1494 | REAL *center) |
1495 | { |
1496 | bool ret = false; |
1497 | |
1498 | REAL kOrigin[3] = { 0, 0, 0 }; |
1499 | |
1500 | REAL wtotal = 0; |
1501 | |
1502 | { |
1503 | const char *source = (const char *) points; |
1504 | const char *wsource = (const char *) weights; |
1505 | |
1506 | for (uint32_t i=0; i<vcount; i++) |
1507 | { |
1508 | |
1509 | const REAL *p = (const REAL *) source; |
1510 | |
1511 | REAL w = 1; |
1512 | |
1513 | if ( wsource ) |
1514 | { |
1515 | const REAL *ws = (const REAL *) wsource; |
1516 | w = *ws; // |
1517 | wsource+=wstride; |
1518 | } |
1519 | |
1520 | kOrigin[0]+=p[0]*w; |
1521 | kOrigin[1]+=p[1]*w; |
1522 | kOrigin[2]+=p[2]*w; |
1523 | |
1524 | wtotal+=w; |
1525 | |
1526 | source+=vstride; |
1527 | } |
1528 | } |
1529 | |
1530 | REAL recip = 1.0f / wtotal; // reciprocol of total weighting |
1531 | |
1532 | kOrigin[0]*=recip; |
1533 | kOrigin[1]*=recip; |
1534 | kOrigin[2]*=recip; |
1535 | |
1536 | center[0] = kOrigin[0]; |
1537 | center[1] = kOrigin[1]; |
1538 | center[2] = kOrigin[2]; |
1539 | |
1540 | |
1541 | REAL fSumXX=0; |
1542 | REAL fSumXY=0; |
1543 | REAL fSumXZ=0; |
1544 | |
1545 | REAL fSumYY=0; |
1546 | REAL fSumYZ=0; |
1547 | REAL fSumZZ=0; |
1548 | |
1549 | |
1550 | { |
1551 | const char *source = (const char *) points; |
1552 | const char *wsource = (const char *) weights; |
1553 | |
1554 | for (uint32_t i=0; i<vcount; i++) |
1555 | { |
1556 | |
1557 | const REAL *p = (const REAL *) source; |
1558 | |
1559 | REAL w = 1; |
1560 | |
1561 | if ( wsource ) |
1562 | { |
1563 | const REAL *ws = (const REAL *) wsource; |
1564 | w = *ws; // |
1565 | wsource+=wstride; |
1566 | } |
1567 | |
1568 | REAL kDiff[3]; |
1569 | |
1570 | kDiff[0] = w*(p[0] - kOrigin[0]); // apply vertex weighting! |
1571 | kDiff[1] = w*(p[1] - kOrigin[1]); |
1572 | kDiff[2] = w*(p[2] - kOrigin[2]); |
1573 | |
1574 | fSumXX+= kDiff[0] * kDiff[0]; // sume of the squares of the differences. |
1575 | fSumXY+= kDiff[0] * kDiff[1]; // sume of the squares of the differences. |
1576 | fSumXZ+= kDiff[0] * kDiff[2]; // sume of the squares of the differences. |
1577 | |
1578 | fSumYY+= kDiff[1] * kDiff[1]; |
1579 | fSumYZ+= kDiff[1] * kDiff[2]; |
1580 | fSumZZ+= kDiff[2] * kDiff[2]; |
1581 | |
1582 | |
1583 | source+=vstride; |
1584 | } |
1585 | } |
1586 | |
1587 | fSumXX *= recip; |
1588 | fSumXY *= recip; |
1589 | fSumXZ *= recip; |
1590 | fSumYY *= recip; |
1591 | fSumYZ *= recip; |
1592 | fSumZZ *= recip; |
1593 | |
1594 | // setup the eigensolver |
1595 | Eigen<REAL> kES; |
1596 | |
1597 | kES.mElement[0][0] = fSumXX; |
1598 | kES.mElement[0][1] = fSumXY; |
1599 | kES.mElement[0][2] = fSumXZ; |
1600 | |
1601 | kES.mElement[1][0] = fSumXY; |
1602 | kES.mElement[1][1] = fSumYY; |
1603 | kES.mElement[1][2] = fSumYZ; |
1604 | |
1605 | kES.mElement[2][0] = fSumXZ; |
1606 | kES.mElement[2][1] = fSumYZ; |
1607 | kES.mElement[2][2] = fSumZZ; |
1608 | |
1609 | // compute eigenstuff, smallest eigenvalue is in last position |
1610 | kES.DecrSortEigenStuff(); |
1611 | |
1612 | REAL kNormal[3]; |
1613 | |
1614 | kNormal[0] = kES.mElement[0][2]; |
1615 | kNormal[1] = kES.mElement[1][2]; |
1616 | kNormal[2] = kES.mElement[2][2]; |
1617 | |
1618 | // the minimum energy |
1619 | plane[0] = kNormal[0]; |
1620 | plane[1] = kNormal[1]; |
1621 | plane[2] = kNormal[2]; |
1622 | |
1623 | plane[3] = 0 - fm_dot(kNormal,kOrigin); |
1624 | |
1625 | ret = true; |
1626 | |
1627 | return ret; |
1628 | } |
1629 | |
1630 | |
1631 | bool fm_colinear(const REAL a1[3],const REAL a2[3],const REAL b1[3],const REAL b2[3],REAL epsilon) // true if these two line segments are co-linear. |
1632 | { |
1633 | bool ret = false; |
1634 | |
1635 | REAL dir1[3]; |
1636 | REAL dir2[3]; |
1637 | |
1638 | dir1[0] = (a2[0] - a1[0]); |
1639 | dir1[1] = (a2[1] - a1[1]); |
1640 | dir1[2] = (a2[2] - a1[2]); |
1641 | |
1642 | dir2[0] = (b2[0]-a1[0]) - (b1[0]-a1[0]); |
1643 | dir2[1] = (b2[1]-a1[1]) - (b1[1]-a1[1]); |
1644 | dir2[2] = (b2[2]-a2[2]) - (b1[2]-a2[2]); |
1645 | |
1646 | fm_normalize(dir1); |
1647 | fm_normalize(dir2); |
1648 | |
1649 | REAL dot = fm_dot(dir1,dir2); |
1650 | |
1651 | if ( dot >= epsilon ) |
1652 | { |
1653 | ret = true; |
1654 | } |
1655 | |
1656 | |
1657 | return ret; |
1658 | } |
1659 | |
1660 | bool fm_colinear(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) |
1661 | { |
1662 | bool ret = false; |
1663 | |
1664 | REAL dir1[3]; |
1665 | REAL dir2[3]; |
1666 | |
1667 | dir1[0] = p2[0] - p1[0]; |
1668 | dir1[1] = p2[1] - p1[1]; |
1669 | dir1[2] = p2[2] - p1[2]; |
1670 | |
1671 | dir2[0] = p3[0] - p2[0]; |
1672 | dir2[1] = p3[1] - p2[1]; |
1673 | dir2[2] = p3[2] - p2[2]; |
1674 | |
1675 | fm_normalize(dir1); |
1676 | fm_normalize(dir2); |
1677 | |
1678 | REAL dot = fm_dot(dir1,dir2); |
1679 | |
1680 | if ( dot >= epsilon ) |
1681 | { |
1682 | ret = true; |
1683 | } |
1684 | |
1685 | |
1686 | return ret; |
1687 | } |
1688 | |
1689 | void fm_initMinMax(const REAL *p,REAL *bmin,REAL *bmax) |
1690 | { |
1691 | bmax[0] = bmin[0] = p[0]; |
1692 | bmax[1] = bmin[1] = p[1]; |
1693 | bmax[2] = bmin[2] = p[2]; |
1694 | } |
1695 | |
1696 | IntersectResult fm_intersectLineSegments2d(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL *intersection) |
1697 | { |
1698 | IntersectResult ret; |
1699 | |
1700 | REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); |
1701 | REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); |
1702 | REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); |
1703 | if (denom == 0 ) |
1704 | { |
1705 | if(nume_a == 0 && nume_b == 0) |
1706 | { |
1707 | ret = IR_COINCIDENT; |
1708 | } |
1709 | else |
1710 | { |
1711 | ret = IR_PARALLEL; |
1712 | } |
1713 | } |
1714 | else |
1715 | { |
1716 | |
1717 | REAL recip = 1 / denom; |
1718 | REAL ua = nume_a * recip; |
1719 | REAL ub = nume_b * recip; |
1720 | |
1721 | if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) |
1722 | { |
1723 | // Get the intersection point. |
1724 | intersection[0] = a1[0] + ua*(a2[0] - a1[0]); |
1725 | intersection[1] = a1[1] + ua*(a2[1] - a1[1]); |
1726 | ret = IR_DO_INTERSECT; |
1727 | } |
1728 | else |
1729 | { |
1730 | ret = IR_DONT_INTERSECT; |
1731 | } |
1732 | } |
1733 | return ret; |
1734 | } |
1735 | |
1736 | IntersectResult fm_intersectLineSegments2dTime(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL &t1,REAL &t2) |
1737 | { |
1738 | IntersectResult ret; |
1739 | |
1740 | REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); |
1741 | REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); |
1742 | REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); |
1743 | if (denom == 0 ) |
1744 | { |
1745 | if(nume_a == 0 && nume_b == 0) |
1746 | { |
1747 | ret = IR_COINCIDENT; |
1748 | } |
1749 | else |
1750 | { |
1751 | ret = IR_PARALLEL; |
1752 | } |
1753 | } |
1754 | else |
1755 | { |
1756 | |
1757 | REAL recip = 1 / denom; |
1758 | REAL ua = nume_a * recip; |
1759 | REAL ub = nume_b * recip; |
1760 | |
1761 | if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) |
1762 | { |
1763 | t1 = ua; |
1764 | t2 = ub; |
1765 | ret = IR_DO_INTERSECT; |
1766 | } |
1767 | else |
1768 | { |
1769 | ret = IR_DONT_INTERSECT; |
1770 | } |
1771 | } |
1772 | return ret; |
1773 | } |
1774 | |
1775 | //**** Plane Triangle Intersection |
1776 | |
1777 | |
1778 | |
1779 | |
1780 | |
1781 | // assumes that the points are on opposite sides of the plane! |
1782 | bool fm_intersectPointPlane(const REAL *p1,const REAL *p2,REAL *split,const REAL *plane) |
1783 | { |
1784 | |
1785 | REAL dp1 = fm_distToPlane(plane,p1); |
1786 | REAL dp2 = fm_distToPlane(plane, p2); |
1787 | if (dp1 <= 0 && dp2 <= 0) |
1788 | { |
1789 | return false; |
1790 | } |
1791 | if (dp1 >= 0 && dp2 >= 0) |
1792 | { |
1793 | return false; |
1794 | } |
1795 | |
1796 | REAL dir[3]; |
1797 | |
1798 | dir[0] = p2[0] - p1[0]; |
1799 | dir[1] = p2[1] - p1[1]; |
1800 | dir[2] = p2[2] - p1[2]; |
1801 | |
1802 | REAL dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2]; |
1803 | REAL dot2 = dp1 - plane[3]; |
1804 | |
1805 | REAL t = -(plane[3] + dot2 ) / dot1; |
1806 | |
1807 | split[0] = (dir[0]*t)+p1[0]; |
1808 | split[1] = (dir[1]*t)+p1[1]; |
1809 | split[2] = (dir[2]*t)+p1[2]; |
1810 | |
1811 | return true; |
1812 | } |
1813 | |
1814 | PlaneTriResult fm_getSidePlane(const REAL *p,const REAL *plane,REAL epsilon) |
1815 | { |
1816 | PlaneTriResult ret = PTR_ON_PLANE; |
1817 | |
1818 | REAL d = fm_distToPlane(plane,p); |
1819 | |
1820 | if ( d < -epsilon || d > epsilon ) |
1821 | { |
1822 | if ( d > 0 ) |
1823 | ret = PTR_FRONT; // it is 'in front' within the provided epsilon value. |
1824 | else |
1825 | ret = PTR_BACK; |
1826 | } |
1827 | |
1828 | return ret; |
1829 | } |
1830 | |
1831 | |
1832 | |
1833 | #ifndef PLANE_TRIANGLE_INTERSECTION_H |
1834 | |
1835 | #define PLANE_TRIANGLE_INTERSECTION_H |
1836 | |
1837 | #define MAXPTS 256 |
1838 | |
1839 | template <class Type> class point |
1840 | { |
1841 | public: |
1842 | |
1843 | void set(const Type *p) |
1844 | { |
1845 | x = p[0]; |
1846 | y = p[1]; |
1847 | z = p[2]; |
1848 | } |
1849 | |
1850 | Type x; |
1851 | Type y; |
1852 | Type z; |
1853 | }; |
1854 | |
1855 | template <class Type> class plane |
1856 | { |
1857 | public: |
1858 | plane(const Type *p) |
1859 | { |
1860 | normal.x = p[0]; |
1861 | normal.y = p[1]; |
1862 | normal.z = p[2]; |
1863 | D = p[3]; |
1864 | } |
1865 | |
1866 | Type Classify_Point(const point<Type> &p) |
1867 | { |
1868 | return p.x*normal.x + p.y*normal.y + p.z*normal.z + D; |
1869 | } |
1870 | |
1871 | point<Type> normal; |
1872 | Type D; |
1873 | }; |
1874 | |
1875 | template <class Type> class polygon |
1876 | { |
1877 | public: |
1878 | polygon(void) |
1879 | { |
1880 | mVcount = 0; |
1881 | } |
1882 | |
1883 | polygon(const Type *p1,const Type *p2,const Type *p3) |
1884 | { |
1885 | mVcount = 3; |
1886 | mVertices[0].set(p1); |
1887 | mVertices[1].set(p2); |
1888 | mVertices[2].set(p3); |
1889 | } |
1890 | |
1891 | |
1892 | int32_t NumVertices(void) const { return mVcount; }; |
1893 | |
1894 | const point<Type>& Vertex(int32_t index) |
1895 | { |
1896 | if ( index < 0 ) index+=mVcount; |
1897 | return mVertices[index]; |
1898 | }; |
1899 | |
1900 | |
1901 | void set(const point<Type> *pts,int32_t count) |
1902 | { |
1903 | for (int32_t i=0; i<count; i++) |
1904 | { |
1905 | mVertices[i] = pts[i]; |
1906 | } |
1907 | mVcount = count; |
1908 | } |
1909 | |
1910 | |
1911 | void Split_Polygon(polygon<Type> *poly,plane<Type> *part, polygon<Type> &front, polygon<Type> &back) |
1912 | { |
1913 | int32_t count = poly->NumVertices (); |
1914 | int32_t out_c = 0, in_c = 0; |
1915 | point<Type> ptA, ptB,outpts[MAXPTS],inpts[MAXPTS]; |
1916 | Type sideA, sideB; |
1917 | ptA = poly->Vertex (count - 1); |
1918 | sideA = part->Classify_Point (ptA); |
1919 | for (int32_t i = -1; ++i < count;) |
1920 | { |
1921 | ptB = poly->Vertex(i); |
1922 | sideB = part->Classify_Point(ptB); |
1923 | if (sideB > 0) |
1924 | { |
1925 | if (sideA < 0) |
1926 | { |
1927 | point<Type> v; |
1928 | fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); |
1929 | outpts[out_c++] = inpts[in_c++] = v; |
1930 | } |
1931 | outpts[out_c++] = ptB; |
1932 | } |
1933 | else if (sideB < 0) |
1934 | { |
1935 | if (sideA > 0) |
1936 | { |
1937 | point<Type> v; |
1938 | fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); |
1939 | outpts[out_c++] = inpts[in_c++] = v; |
1940 | } |
1941 | inpts[in_c++] = ptB; |
1942 | } |
1943 | else |
1944 | outpts[out_c++] = inpts[in_c++] = ptB; |
1945 | ptA = ptB; |
1946 | sideA = sideB; |
1947 | } |
1948 | |
1949 | front.set(&outpts[0], out_c); |
1950 | back.set(&inpts[0], in_c); |
1951 | } |
1952 | |
1953 | int32_t mVcount; |
1954 | point<Type> mVertices[MAXPTS]; |
1955 | }; |
1956 | |
1957 | |
1958 | |
1959 | #endif |
1960 | |
1961 | static inline void add(const REAL *p,REAL *dest,uint32_t tstride,uint32_t &pcount) |
1962 | { |
1963 | char *d = (char *) dest; |
1964 | d = d + pcount*tstride; |
1965 | dest = (REAL *) d; |
1966 | dest[0] = p[0]; |
1967 | dest[1] = p[1]; |
1968 | dest[2] = p[2]; |
1969 | pcount++; |
1970 | assert( pcount <= 4 ); |
1971 | } |
1972 | |
1973 | |
1974 | PlaneTriResult fm_planeTriIntersection(const REAL *_plane, // the plane equation in Ax+By+Cz+D format |
1975 | const REAL *triangle, // the source triangle. |
1976 | uint32_t tstride, // stride in bytes of the input and output *vertices* |
1977 | REAL epsilon, // the co-planar epsilon value. |
1978 | REAL *front, // the triangle in front of the |
1979 | uint32_t &fcount, // number of vertices in the 'front' triangle |
1980 | REAL *back, // the triangle in back of the plane |
1981 | uint32_t &bcount) // the number of vertices in the 'back' triangle. |
1982 | { |
1983 | |
1984 | fcount = 0; |
1985 | bcount = 0; |
1986 | |
1987 | const char *tsource = (const char *) triangle; |
1988 | |
1989 | // get the three vertices of the triangle. |
1990 | const REAL *p1 = (const REAL *) (tsource); |
1991 | const REAL *p2 = (const REAL *) (tsource+tstride); |
1992 | const REAL *p3 = (const REAL *) (tsource+tstride*2); |
1993 | |
1994 | |
1995 | PlaneTriResult r1 = fm_getSidePlane(p1,_plane,epsilon); // compute the side of the plane each vertex is on |
1996 | PlaneTriResult r2 = fm_getSidePlane(p2,_plane,epsilon); |
1997 | PlaneTriResult r3 = fm_getSidePlane(p3,_plane,epsilon); |
1998 | |
1999 | // If any of the points lay right *on* the plane.... |
2000 | if ( r1 == PTR_ON_PLANE || r2 == PTR_ON_PLANE || r3 == PTR_ON_PLANE ) |
2001 | { |
2002 | // If the triangle is completely co-planar, then just treat it as 'front' and return! |
2003 | if ( r1 == PTR_ON_PLANE && r2 == PTR_ON_PLANE && r3 == PTR_ON_PLANE ) |
2004 | { |
2005 | add(p1,front,tstride,fcount); |
2006 | add(p2,front,tstride,fcount); |
2007 | add(p3,front,tstride,fcount); |
2008 | return PTR_FRONT; |
2009 | } |
2010 | // Decide to place the co-planar points on the same side as the co-planar point. |
2011 | PlaneTriResult r= PTR_ON_PLANE; |
2012 | if ( r1 != PTR_ON_PLANE ) |
2013 | r = r1; |
2014 | else if ( r2 != PTR_ON_PLANE ) |
2015 | r = r2; |
2016 | else if ( r3 != PTR_ON_PLANE ) |
2017 | r = r3; |
2018 | |
2019 | if ( r1 == PTR_ON_PLANE ) r1 = r; |
2020 | if ( r2 == PTR_ON_PLANE ) r2 = r; |
2021 | if ( r3 == PTR_ON_PLANE ) r3 = r; |
2022 | |
2023 | } |
2024 | |
2025 | if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane. |
2026 | { |
2027 | if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle. |
2028 | { |
2029 | add(p1,front,tstride,fcount); |
2030 | add(p2,front,tstride,fcount); |
2031 | add(p3,front,tstride,fcount); |
2032 | } |
2033 | else |
2034 | { |
2035 | add(p1,back,tstride,bcount); // if all three are in 'back' then copy to the 'back' output triangle. |
2036 | add(p2,back,tstride,bcount); |
2037 | add(p3,back,tstride,bcount); |
2038 | } |
2039 | return r1; // if all three points are on the same side of the plane return result |
2040 | } |
2041 | |
2042 | |
2043 | polygon<REAL> pi(p1,p2,p3); |
2044 | polygon<REAL> pfront,pback; |
2045 | |
2046 | plane<REAL> part(_plane); |
2047 | |
2048 | pi.Split_Polygon(&pi,&part,pfront,pback); |
2049 | |
2050 | for (int32_t i=0; i<pfront.mVcount; i++) |
2051 | { |
2052 | add( &pfront.mVertices[i].x, front, tstride, fcount ); |
2053 | } |
2054 | |
2055 | for (int32_t i=0; i<pback.mVcount; i++) |
2056 | { |
2057 | add( &pback.mVertices[i].x, back, tstride, bcount ); |
2058 | } |
2059 | |
2060 | PlaneTriResult ret = PTR_SPLIT; |
2061 | |
2062 | if ( fcount < 3 ) fcount = 0; |
2063 | if ( bcount < 3 ) bcount = 0; |
2064 | |
2065 | if ( fcount == 0 && bcount ) |
2066 | ret = PTR_BACK; |
2067 | |
2068 | if ( bcount == 0 && fcount ) |
2069 | ret = PTR_FRONT; |
2070 | |
2071 | |
2072 | return ret; |
2073 | } |
2074 | |
2075 | // computes the OBB for this set of points relative to this transform matrix. |
2076 | void computeOBB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *matrix) |
2077 | { |
2078 | const char *src = (const char *) points; |
2079 | |
2080 | REAL bmin[3] = { 1e9, 1e9, 1e9 }; |
2081 | REAL bmax[3] = { -1e9, -1e9, -1e9 }; |
2082 | |
2083 | for (uint32_t i=0; i<vcount; i++) |
2084 | { |
2085 | const REAL *p = (const REAL *) src; |
2086 | REAL t[3]; |
2087 | |
2088 | fm_inverseRT(matrix, p, t ); // inverse rotate translate |
2089 | |
2090 | if ( t[0] < bmin[0] ) bmin[0] = t[0]; |
2091 | if ( t[1] < bmin[1] ) bmin[1] = t[1]; |
2092 | if ( t[2] < bmin[2] ) bmin[2] = t[2]; |
2093 | |
2094 | if ( t[0] > bmax[0] ) bmax[0] = t[0]; |
2095 | if ( t[1] > bmax[1] ) bmax[1] = t[1]; |
2096 | if ( t[2] > bmax[2] ) bmax[2] = t[2]; |
2097 | |
2098 | src+=pstride; |
2099 | } |
2100 | |
2101 | REAL center[3]; |
2102 | |
2103 | sides[0] = bmax[0]-bmin[0]; |
2104 | sides[1] = bmax[1]-bmin[1]; |
2105 | sides[2] = bmax[2]-bmin[2]; |
2106 | |
2107 | center[0] = sides[0]*0.5f+bmin[0]; |
2108 | center[1] = sides[1]*0.5f+bmin[1]; |
2109 | center[2] = sides[2]*0.5f+bmin[2]; |
2110 | |
2111 | REAL ocenter[3]; |
2112 | |
2113 | fm_rotate(matrix,center,ocenter); |
2114 | |
2115 | matrix[12]+=ocenter[0]; |
2116 | matrix[13]+=ocenter[1]; |
2117 | matrix[14]+=ocenter[2]; |
2118 | |
2119 | } |
2120 | |
2121 | void fm_computeBestFitOBB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *matrix,bool bruteForce) |
2122 | { |
2123 | REAL plane[4]; |
2124 | REAL center[3]; |
2125 | fm_computeBestFitPlane(vcount,points,pstride,0,0,plane,center); |
2126 | fm_planeToMatrix(plane,matrix); |
2127 | computeOBB( vcount, points, pstride, sides, matrix ); |
2128 | |
2129 | REAL refmatrix[16]; |
2130 | memcpy(refmatrix,matrix,16*sizeof(REAL)); |
2131 | |
2132 | REAL volume = sides[0]*sides[1]*sides[2]; |
2133 | if ( bruteForce ) |
2134 | { |
2135 | for (REAL a=10; a<180; a+=10) |
2136 | { |
2137 | REAL quat[4]; |
2138 | fm_eulerToQuat(0,a*FM_DEG_TO_RAD,0,quat); |
2139 | REAL temp[16]; |
2140 | REAL pmatrix[16]; |
2141 | fm_quatToMatrix(quat,temp); |
2142 | fm_matrixMultiply(temp,refmatrix,pmatrix); |
2143 | REAL psides[3]; |
2144 | computeOBB( vcount, points, pstride, psides, pmatrix ); |
2145 | REAL v = psides[0]*psides[1]*psides[2]; |
2146 | if ( v < volume ) |
2147 | { |
2148 | volume = v; |
2149 | memcpy(matrix,pmatrix,sizeof(REAL)*16); |
2150 | sides[0] = psides[0]; |
2151 | sides[1] = psides[1]; |
2152 | sides[2] = psides[2]; |
2153 | } |
2154 | } |
2155 | } |
2156 | } |
2157 | |
2158 | void fm_computeBestFitOBB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *pos,REAL *quat,bool bruteForce) |
2159 | { |
2160 | REAL matrix[16]; |
2161 | fm_computeBestFitOBB(vcount,points,pstride,sides,matrix,bruteForce); |
2162 | fm_getTranslation(matrix,pos); |
2163 | fm_matrixToQuat(matrix,quat); |
2164 | } |
2165 | |
2166 | void fm_computeBestFitABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *pos) |
2167 | { |
2168 | REAL bmin[3]; |
2169 | REAL bmax[3]; |
2170 | |
2171 | bmin[0] = points[0]; |
2172 | bmin[1] = points[1]; |
2173 | bmin[2] = points[2]; |
2174 | |
2175 | bmax[0] = points[0]; |
2176 | bmax[1] = points[1]; |
2177 | bmax[2] = points[2]; |
2178 | |
2179 | const char *cp = (const char *) points; |
2180 | for (uint32_t i=0; i<vcount; i++) |
2181 | { |
2182 | const REAL *p = (const REAL *) cp; |
2183 | |
2184 | if ( p[0] < bmin[0] ) bmin[0] = p[0]; |
2185 | if ( p[1] < bmin[1] ) bmin[1] = p[1]; |
2186 | if ( p[2] < bmin[2] ) bmin[2] = p[2]; |
2187 | |
2188 | if ( p[0] > bmax[0] ) bmax[0] = p[0]; |
2189 | if ( p[1] > bmax[1] ) bmax[1] = p[1]; |
2190 | if ( p[2] > bmax[2] ) bmax[2] = p[2]; |
2191 | |
2192 | cp+=pstride; |
2193 | } |
2194 | |
2195 | |
2196 | sides[0] = bmax[0] - bmin[0]; |
2197 | sides[1] = bmax[1] - bmin[1]; |
2198 | sides[2] = bmax[2] - bmin[2]; |
2199 | |
2200 | pos[0] = bmin[0]+sides[0]*0.5f; |
2201 | pos[1] = bmin[1]+sides[1]*0.5f; |
2202 | pos[2] = bmin[2]+sides[2]*0.5f; |
2203 | |
2204 | } |
2205 | |
2206 | |
2207 | void fm_planeToMatrix(const REAL *plane,REAL *matrix) // convert a plane equation to a 4x4 rotation matrix |
2208 | { |
2209 | REAL ref[3] = { 0, 1, 0 }; |
2210 | REAL quat[4]; |
2211 | fm_rotationArc(ref,plane,quat); |
2212 | fm_quatToMatrix(quat,matrix); |
2213 | REAL origin[3] = { 0, -plane[3], 0 }; |
2214 | REAL center[3]; |
2215 | fm_transform(matrix,origin,center); |
2216 | fm_setTranslation(center,matrix); |
2217 | } |
2218 | |
2219 | void fm_planeToQuat(const REAL *plane,REAL *quat,REAL *pos) // convert a plane equation to a quaternion and translation |
2220 | { |
2221 | REAL ref[3] = { 0, 1, 0 }; |
2222 | REAL matrix[16]; |
2223 | fm_rotationArc(ref,plane,quat); |
2224 | fm_quatToMatrix(quat,matrix); |
2225 | REAL origin[3] = { 0, plane[3], 0 }; |
2226 | fm_transform(matrix,origin,pos); |
2227 | } |
2228 | |
2229 | void fm_eulerMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) |
2230 | { |
2231 | REAL quat[4]; |
2232 | fm_eulerToQuat(ax,ay,az,quat); |
2233 | fm_quatToMatrix(quat,matrix); |
2234 | } |
2235 | |
2236 | |
2237 | //********************************************************** |
2238 | //********************************************************** |
2239 | //**** Vertex Welding |
2240 | //********************************************************** |
2241 | //********************************************************** |
2242 | |
2243 | #ifndef VERTEX_INDEX_H |
2244 | |
2245 | #define VERTEX_INDEX_H |
2246 | |
2247 | namespace VERTEX_INDEX |
2248 | { |
2249 | |
2250 | class KdTreeNode; |
2251 | |
2252 | typedef std::vector< KdTreeNode * > KdTreeNodeVector; |
2253 | |
2254 | enum Axes |
2255 | { |
2256 | X_AXIS = 0, |
2257 | Y_AXIS = 1, |
2258 | Z_AXIS = 2 |
2259 | }; |
2260 | |
2261 | class KdTreeFindNode |
2262 | { |
2263 | public: |
2264 | KdTreeFindNode(void) |
2265 | { |
2266 | mNode = 0; |
2267 | mDistance = 0; |
2268 | } |
2269 | KdTreeNode *mNode; |
2270 | double mDistance; |
2271 | }; |
2272 | |
2273 | class KdTreeInterface |
2274 | { |
2275 | public: |
2276 | virtual const double * getPositionDouble(uint32_t index) const = 0; |
2277 | virtual const float * getPositionFloat(uint32_t index) const = 0; |
2278 | }; |
2279 | |
2280 | class KdTreeNode |
2281 | { |
2282 | public: |
2283 | KdTreeNode(void) |
2284 | { |
2285 | mIndex = 0; |
2286 | mLeft = 0; |
2287 | mRight = 0; |
2288 | } |
2289 | |
2290 | KdTreeNode(uint32_t index) |
2291 | { |
2292 | mIndex = index; |
2293 | mLeft = 0; |
2294 | mRight = 0; |
2295 | }; |
2296 | |
2297 | ~KdTreeNode(void) |
2298 | { |
2299 | } |
2300 | |
2301 | |
2302 | void addDouble(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) |
2303 | { |
2304 | const double *nodePosition = iface->getPositionDouble( node->mIndex ); |
2305 | const double *position = iface->getPositionDouble( mIndex ); |
2306 | switch ( dim ) |
2307 | { |
2308 | case X_AXIS: |
2309 | if ( nodePosition[0] <= position[0] ) |
2310 | { |
2311 | if ( mLeft ) |
2312 | mLeft->addDouble(node,Y_AXIS,iface); |
2313 | else |
2314 | mLeft = node; |
2315 | } |
2316 | else |
2317 | { |
2318 | if ( mRight ) |
2319 | mRight->addDouble(node,Y_AXIS,iface); |
2320 | else |
2321 | mRight = node; |
2322 | } |
2323 | break; |
2324 | case Y_AXIS: |
2325 | if ( nodePosition[1] <= position[1] ) |
2326 | { |
2327 | if ( mLeft ) |
2328 | mLeft->addDouble(node,Z_AXIS,iface); |
2329 | else |
2330 | mLeft = node; |
2331 | } |
2332 | else |
2333 | { |
2334 | if ( mRight ) |
2335 | mRight->addDouble(node,Z_AXIS,iface); |
2336 | else |
2337 | mRight = node; |
2338 | } |
2339 | break; |
2340 | case Z_AXIS: |
2341 | if ( nodePosition[2] <= position[2] ) |
2342 | { |
2343 | if ( mLeft ) |
2344 | mLeft->addDouble(node,X_AXIS,iface); |
2345 | else |
2346 | mLeft = node; |
2347 | } |
2348 | else |
2349 | { |
2350 | if ( mRight ) |
2351 | mRight->addDouble(node,X_AXIS,iface); |
2352 | else |
2353 | mRight = node; |
2354 | } |
2355 | break; |
2356 | } |
2357 | |
2358 | } |
2359 | |
2360 | |
2361 | void addFloat(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) |
2362 | { |
2363 | const float *nodePosition = iface->getPositionFloat( node->mIndex ); |
2364 | const float *position = iface->getPositionFloat( mIndex ); |
2365 | switch ( dim ) |
2366 | { |
2367 | case X_AXIS: |
2368 | if ( nodePosition[0] <= position[0] ) |
2369 | { |
2370 | if ( mLeft ) |
2371 | mLeft->addFloat(node,Y_AXIS,iface); |
2372 | else |
2373 | mLeft = node; |
2374 | } |
2375 | else |
2376 | { |
2377 | if ( mRight ) |
2378 | mRight->addFloat(node,Y_AXIS,iface); |
2379 | else |
2380 | mRight = node; |
2381 | } |
2382 | break; |
2383 | case Y_AXIS: |
2384 | if ( nodePosition[1] <= position[1] ) |
2385 | { |
2386 | if ( mLeft ) |
2387 | mLeft->addFloat(node,Z_AXIS,iface); |
2388 | else |
2389 | mLeft = node; |
2390 | } |
2391 | else |
2392 | { |
2393 | if ( mRight ) |
2394 | mRight->addFloat(node,Z_AXIS,iface); |
2395 | else |
2396 | mRight = node; |
2397 | } |
2398 | break; |
2399 | case Z_AXIS: |
2400 | if ( nodePosition[2] <= position[2] ) |
2401 | { |
2402 | if ( mLeft ) |
2403 | mLeft->addFloat(node,X_AXIS,iface); |
2404 | else |
2405 | mLeft = node; |
2406 | } |
2407 | else |
2408 | { |
2409 | if ( mRight ) |
2410 | mRight->addFloat(node,X_AXIS,iface); |
2411 | else |
2412 | mRight = node; |
2413 | } |
2414 | break; |
2415 | } |
2416 | |
2417 | } |
2418 | |
2419 | |
2420 | uint32_t getIndex(void) const { return mIndex; }; |
2421 | |
2422 | void search(Axes axis,const double *pos,double radius,uint32_t &count,uint32_t maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) |
2423 | { |
2424 | |
2425 | const double *position = iface->getPositionDouble(mIndex); |
2426 | |
2427 | double dx = pos[0] - position[0]; |
2428 | double dy = pos[1] - position[1]; |
2429 | double dz = pos[2] - position[2]; |
2430 | |
2431 | KdTreeNode *search1 = 0; |
2432 | KdTreeNode *search2 = 0; |
2433 | |
2434 | switch ( axis ) |
2435 | { |
2436 | case X_AXIS: |
2437 | if ( dx <= 0 ) // JWR if we are to the left |
2438 | { |
2439 | search1 = mLeft; // JWR then search to the left |
2440 | if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. |
2441 | search2 = mRight; |
2442 | } |
2443 | else |
2444 | { |
2445 | search1 = mRight; // JWR ok, we go down the left tree |
2446 | if ( dx < radius ) // JWR if the distance from the right is less than our search radius |
2447 | search2 = mLeft; |
2448 | } |
2449 | axis = Y_AXIS; |
2450 | break; |
2451 | case Y_AXIS: |
2452 | if ( dy <= 0 ) |
2453 | { |
2454 | search1 = mLeft; |
2455 | if ( -dy < radius ) |
2456 | search2 = mRight; |
2457 | } |
2458 | else |
2459 | { |
2460 | search1 = mRight; |
2461 | if ( dy < radius ) |
2462 | search2 = mLeft; |
2463 | } |
2464 | axis = Z_AXIS; |
2465 | break; |
2466 | case Z_AXIS: |
2467 | if ( dz <= 0 ) |
2468 | { |
2469 | search1 = mLeft; |
2470 | if ( -dz < radius ) |
2471 | search2 = mRight; |
2472 | } |
2473 | else |
2474 | { |
2475 | search1 = mRight; |
2476 | if ( dz < radius ) |
2477 | search2 = mLeft; |
2478 | } |
2479 | axis = X_AXIS; |
2480 | break; |
2481 | } |
2482 | |
2483 | double r2 = radius*radius; |
2484 | double m = dx*dx+dy*dy+dz*dz; |
2485 | |
2486 | if ( m < r2 ) |
2487 | { |
2488 | switch ( count ) |
2489 | { |
2490 | case 0: |
2491 | found[count].mNode = this; |
2492 | found[count].mDistance = m; |
2493 | break; |
2494 | case 1: |
2495 | if ( m < found[0].mDistance ) |
2496 | { |
2497 | if ( maxObjects == 1 ) |
2498 | { |
2499 | found[0].mNode = this; |
2500 | found[0].mDistance = m; |
2501 | } |
2502 | else |
2503 | { |
2504 | found[1] = found[0]; |
2505 | found[0].mNode = this; |
2506 | found[0].mDistance = m; |
2507 | } |
2508 | } |
2509 | else if ( maxObjects > 1) |
2510 | { |
2511 | found[1].mNode = this; |
2512 | found[1].mDistance = m; |
2513 | } |
2514 | break; |
2515 | default: |
2516 | { |
2517 | bool inserted = false; |
2518 | |
2519 | for (uint32_t i=0; i<count; i++) |
2520 | { |
2521 | if ( m < found[i].mDistance ) // if this one is closer than a pre-existing one... |
2522 | { |
2523 | // insertion sort... |
2524 | uint32_t scan = count; |
2525 | if ( scan >= maxObjects ) scan=maxObjects-1; |
2526 | for (uint32_t j=scan; j>i; j--) |
2527 | { |
2528 | found[j] = found[j-1]; |
2529 | } |
2530 | found[i].mNode = this; |
2531 | found[i].mDistance = m; |
2532 | inserted = true; |
2533 | break; |
2534 | } |
2535 | } |
2536 | |
2537 | if ( !inserted && count < maxObjects ) |
2538 | { |
2539 | found[count].mNode = this; |
2540 | found[count].mDistance = m; |
2541 | } |
2542 | } |
2543 | break; |
2544 | } |
2545 | count++; |
2546 | if ( count > maxObjects ) |
2547 | { |
2548 | count = maxObjects; |
2549 | } |
2550 | } |
2551 | |
2552 | |
2553 | if ( search1 ) |
2554 | search1->search( axis, pos,radius, count, maxObjects, found, iface); |
2555 | |
2556 | if ( search2 ) |
2557 | search2->search( axis, pos,radius, count, maxObjects, found, iface); |
2558 | |
2559 | } |
2560 | |
2561 | void search(Axes axis,const float *pos,float radius,uint32_t &count,uint32_t maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) |
2562 | { |
2563 | |
2564 | const float *position = iface->getPositionFloat(mIndex); |
2565 | |
2566 | float dx = pos[0] - position[0]; |
2567 | float dy = pos[1] - position[1]; |
2568 | float dz = pos[2] - position[2]; |
2569 | |
2570 | KdTreeNode *search1 = 0; |
2571 | KdTreeNode *search2 = 0; |
2572 | |
2573 | switch ( axis ) |
2574 | { |
2575 | case X_AXIS: |
2576 | if ( dx <= 0 ) // JWR if we are to the left |
2577 | { |
2578 | search1 = mLeft; // JWR then search to the left |
2579 | if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. |
2580 | search2 = mRight; |
2581 | } |
2582 | else |
2583 | { |
2584 | search1 = mRight; // JWR ok, we go down the left tree |
2585 | if ( dx < radius ) // JWR if the distance from the right is less than our search radius |
2586 | search2 = mLeft; |
2587 | } |
2588 | axis = Y_AXIS; |
2589 | break; |
2590 | case Y_AXIS: |
2591 | if ( dy <= 0 ) |
2592 | { |
2593 | search1 = mLeft; |
2594 | if ( -dy < radius ) |
2595 | search2 = mRight; |
2596 | } |
2597 | else |
2598 | { |
2599 | search1 = mRight; |
2600 | if ( dy < radius ) |
2601 | search2 = mLeft; |
2602 | } |
2603 | axis = Z_AXIS; |
2604 | break; |
2605 | case Z_AXIS: |
2606 | if ( dz <= 0 ) |
2607 | { |
2608 | search1 = mLeft; |
2609 | if ( -dz < radius ) |
2610 | search2 = mRight; |
2611 | } |
2612 | else |
2613 | { |
2614 | search1 = mRight; |
2615 | if ( dz < radius ) |
2616 | search2 = mLeft; |
2617 | } |
2618 | axis = X_AXIS; |
2619 | break; |
2620 | } |
2621 | |
2622 | float r2 = radius*radius; |
2623 | float m = dx*dx+dy*dy+dz*dz; |
2624 | |
2625 | if ( m < r2 ) |
2626 | { |
2627 | switch ( count ) |
2628 | { |
2629 | case 0: |
2630 | found[count].mNode = this; |
2631 | found[count].mDistance = m; |
2632 | break; |
2633 | case 1: |
2634 | if ( m < found[0].mDistance ) |
2635 | { |
2636 | if ( maxObjects == 1 ) |
2637 | { |
2638 | found[0].mNode = this; |
2639 | found[0].mDistance = m; |
2640 | } |
2641 | else |
2642 | { |
2643 | found[1] = found[0]; |
2644 | found[0].mNode = this; |
2645 | found[0].mDistance = m; |
2646 | } |
2647 | } |
2648 | else if ( maxObjects > 1) |
2649 | { |
2650 | found[1].mNode = this; |
2651 | found[1].mDistance = m; |
2652 | } |
2653 | break; |
2654 | default: |
2655 | { |
2656 | bool inserted = false; |
2657 | |
2658 | for (uint32_t i=0; i<count; i++) |
2659 | { |
2660 | if ( m < found[i].mDistance ) // if this one is closer than a pre-existing one... |
2661 | { |
2662 | // insertion sort... |
2663 | uint32_t scan = count; |
2664 | if ( scan >= maxObjects ) scan=maxObjects-1; |
2665 | for (uint32_t j=scan; j>i; j--) |
2666 | { |
2667 | found[j] = found[j-1]; |
2668 | } |
2669 | found[i].mNode = this; |
2670 | found[i].mDistance = m; |
2671 | inserted = true; |
2672 | break; |
2673 | } |
2674 | } |
2675 | |
2676 | if ( !inserted && count < maxObjects ) |
2677 | { |
2678 | found[count].mNode = this; |
2679 | found[count].mDistance = m; |
2680 | } |
2681 | } |
2682 | break; |
2683 | } |
2684 | count++; |
2685 | if ( count > maxObjects ) |
2686 | { |
2687 | count = maxObjects; |
2688 | } |
2689 | } |
2690 | |
2691 | |
2692 | if ( search1 ) |
2693 | search1->search( axis, pos,radius, count, maxObjects, found, iface); |
2694 | |
2695 | if ( search2 ) |
2696 | search2->search( axis, pos,radius, count, maxObjects, found, iface); |
2697 | |
2698 | } |
2699 | |
2700 | private: |
2701 | |
2702 | void setLeft(KdTreeNode *left) { mLeft = left; }; |
2703 | void setRight(KdTreeNode *right) { mRight = right; }; |
2704 | |
2705 | KdTreeNode *getLeft(void) { return mLeft; } |
2706 | KdTreeNode *getRight(void) { return mRight; } |
2707 | |
2708 | uint32_t mIndex; |
2709 | KdTreeNode *mLeft; |
2710 | KdTreeNode *mRight; |
2711 | }; |
2712 | |
2713 | |
2714 | #define MAX_BUNDLE_SIZE 1024 // 1024 nodes at a time, to minimize memory allocation and guarantee that pointers are persistent. |
2715 | |
2716 | class KdTreeNodeBundle |
2717 | { |
2718 | public: |
2719 | |
2720 | KdTreeNodeBundle(void) |
2721 | { |
2722 | mNext = 0; |
2723 | mIndex = 0; |
2724 | } |
2725 | |
2726 | bool isFull(void) const |
2727 | { |
2728 | return (bool)( mIndex == MAX_BUNDLE_SIZE ); |
2729 | } |
2730 | |
2731 | KdTreeNode * getNextNode(void) |
2732 | { |
2733 | assert(mIndex<MAX_BUNDLE_SIZE); |
2734 | KdTreeNode *ret = &mNodes[mIndex]; |
2735 | mIndex++; |
2736 | return ret; |
2737 | } |
2738 | |
2739 | KdTreeNodeBundle *mNext; |
2740 | uint32_t mIndex; |
2741 | KdTreeNode mNodes[MAX_BUNDLE_SIZE]; |
2742 | }; |
2743 | |
2744 | |
2745 | typedef std::vector< double > DoubleVector; |
2746 | typedef std::vector< float > FloatVector; |
2747 | |
2748 | class KdTree : public KdTreeInterface |
2749 | { |
2750 | public: |
2751 | KdTree(void) |
2752 | { |
2753 | mRoot = 0; |
2754 | mBundle = 0; |
2755 | mVcount = 0; |
2756 | mUseDouble = false; |
2757 | } |
2758 | |
2759 | virtual ~KdTree(void) |
2760 | { |
2761 | reset(); |
2762 | } |
2763 | |
2764 | const double * getPositionDouble(uint32_t index) const |
2765 | { |
2766 | assert( mUseDouble ); |
2767 | assert ( index < mVcount ); |
2768 | return &mVerticesDouble[index*3]; |
2769 | } |
2770 | |
2771 | const float * getPositionFloat(uint32_t index) const |
2772 | { |
2773 | assert( !mUseDouble ); |
2774 | assert ( index < mVcount ); |
2775 | return &mVerticesFloat[index*3]; |
2776 | } |
2777 | |
2778 | uint32_t search(const double *pos,double radius,uint32_t maxObjects,KdTreeFindNode *found) const |
2779 | { |
2780 | assert( mUseDouble ); |
2781 | if ( !mRoot ) return 0; |
2782 | uint32_t count = 0; |
2783 | mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); |
2784 | return count; |
2785 | } |
2786 | |
2787 | uint32_t search(const float *pos,float radius,uint32_t maxObjects,KdTreeFindNode *found) const |
2788 | { |
2789 | assert( !mUseDouble ); |
2790 | if ( !mRoot ) return 0; |
2791 | uint32_t count = 0; |
2792 | mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); |
2793 | return count; |
2794 | } |
2795 | |
2796 | void reset(void) |
2797 | { |
2798 | mRoot = 0; |
2799 | mVerticesDouble.clear(); |
2800 | mVerticesFloat.clear(); |
2801 | KdTreeNodeBundle *bundle = mBundle; |
2802 | while ( bundle ) |
2803 | { |
2804 | KdTreeNodeBundle *next = bundle->mNext; |
2805 | delete bundle; |
2806 | bundle = next; |
2807 | } |
2808 | mBundle = 0; |
2809 | mVcount = 0; |
2810 | } |
2811 | |
2812 | uint32_t add(double x,double y,double z) |
2813 | { |
2814 | assert(mUseDouble); |
2815 | uint32_t ret = mVcount; |
2816 | mVerticesDouble.push_back(x); |
2817 | mVerticesDouble.push_back(y); |
2818 | mVerticesDouble.push_back(z); |
2819 | mVcount++; |
2820 | KdTreeNode *node = getNewNode(ret); |
2821 | if ( mRoot ) |
2822 | { |
2823 | mRoot->addDouble(node,X_AXIS,this); |
2824 | } |
2825 | else |
2826 | { |
2827 | mRoot = node; |
2828 | } |
2829 | return ret; |
2830 | } |
2831 | |
2832 | uint32_t add(float x,float y,float z) |
2833 | { |
2834 | assert(!mUseDouble); |
2835 | uint32_t ret = mVcount; |
2836 | mVerticesFloat.push_back(x); |
2837 | mVerticesFloat.push_back(y); |
2838 | mVerticesFloat.push_back(z); |
2839 | mVcount++; |
2840 | KdTreeNode *node = getNewNode(ret); |
2841 | if ( mRoot ) |
2842 | { |
2843 | mRoot->addFloat(node,X_AXIS,this); |
2844 | } |
2845 | else |
2846 | { |
2847 | mRoot = node; |
2848 | } |
2849 | return ret; |
2850 | } |
2851 | |
2852 | KdTreeNode * getNewNode(uint32_t index) |
2853 | { |
2854 | if ( mBundle == 0 ) |
2855 | { |
2856 | mBundle = new KdTreeNodeBundle; |
2857 | } |
2858 | if ( mBundle->isFull() ) |
2859 | { |
2860 | KdTreeNodeBundle *bundle = new KdTreeNodeBundle; |
2861 | mBundle->mNext = bundle; |
2862 | mBundle = bundle; |
2863 | } |
2864 | KdTreeNode *node = mBundle->getNextNode(); |
2865 | new ( node ) KdTreeNode(index); |
2866 | return node; |
2867 | } |
2868 | |
2869 | uint32_t getNearest(const double *pos,double radius,bool &_found) const // returns the nearest possible neighbor's index. |
2870 | { |
2871 | assert( mUseDouble ); |
2872 | uint32_t ret = 0; |
2873 | |
2874 | _found = false; |
2875 | KdTreeFindNode found[1]; |
2876 | uint32_t count = search(pos,radius,1,found); |
2877 | if ( count ) |
2878 | { |
2879 | KdTreeNode *node = found[0].mNode; |
2880 | ret = node->getIndex(); |
2881 | _found = true; |
2882 | } |
2883 | return ret; |
2884 | } |
2885 | |
2886 | uint32_t getNearest(const float *pos,float radius,bool &_found) const // returns the nearest possible neighbor's index. |
2887 | { |
2888 | assert( !mUseDouble ); |
2889 | uint32_t ret = 0; |
2890 | |
2891 | _found = false; |
2892 | KdTreeFindNode found[1]; |
2893 | uint32_t count = search(pos,radius,1,found); |
2894 | if ( count ) |
2895 | { |
2896 | KdTreeNode *node = found[0].mNode; |
2897 | ret = node->getIndex(); |
2898 | _found = true; |
2899 | } |
2900 | return ret; |
2901 | } |
2902 | |
2903 | const double * getVerticesDouble(void) const |
2904 | { |
2905 | assert( mUseDouble ); |
2906 | const double *ret = 0; |
2907 | if ( !mVerticesDouble.empty() ) |
2908 | { |
2909 | ret = &mVerticesDouble[0]; |
2910 | } |
2911 | return ret; |
2912 | } |
2913 | |
2914 | const float * getVerticesFloat(void) const |
2915 | { |
2916 | assert( !mUseDouble ); |
2917 | const float * ret = 0; |
2918 | if ( !mVerticesFloat.empty() ) |
2919 | { |
2920 | ret = &mVerticesFloat[0]; |
2921 | } |
2922 | return ret; |
2923 | } |
2924 | |
2925 | uint32_t getVcount(void) const { return mVcount; }; |
2926 | |
2927 | void setUseDouble(bool useDouble) |
2928 | { |
2929 | mUseDouble = useDouble; |
2930 | } |
2931 | |
2932 | private: |
2933 | bool mUseDouble; |
2934 | KdTreeNode *mRoot; |
2935 | KdTreeNodeBundle *mBundle; |
2936 | uint32_t mVcount; |
2937 | DoubleVector mVerticesDouble; |
2938 | FloatVector mVerticesFloat; |
2939 | }; |
2940 | |
2941 | }; // end of namespace VERTEX_INDEX |
2942 | |
2943 | class MyVertexIndex : public fm_VertexIndex |
2944 | { |
2945 | public: |
2946 | MyVertexIndex(double granularity,bool snapToGrid) |
2947 | { |
2948 | mDoubleGranularity = granularity; |
2949 | mFloatGranularity = (float)granularity; |
2950 | mSnapToGrid = snapToGrid; |
2951 | mUseDouble = true; |
2952 | mKdTree.setUseDouble(true); |
2953 | } |
2954 | |
2955 | MyVertexIndex(float granularity,bool snapToGrid) |
2956 | { |
2957 | mDoubleGranularity = granularity; |
2958 | mFloatGranularity = (float)granularity; |
2959 | mSnapToGrid = snapToGrid; |
2960 | mUseDouble = false; |
2961 | mKdTree.setUseDouble(false); |
2962 | } |
2963 | |
2964 | virtual ~MyVertexIndex(void) |
2965 | { |
2966 | |
2967 | } |
2968 | |
2969 | |
2970 | double snapToGrid(double p) |
2971 | { |
2972 | double m = fmod(p,mDoubleGranularity); |
2973 | p-=m; |
2974 | return p; |
2975 | } |
2976 | |
2977 | float snapToGrid(float p) |
2978 | { |
2979 | float m = fmodf(p,mFloatGranularity); |
2980 | p-=m; |
2981 | return p; |
2982 | } |
2983 | |
2984 | uint32_t getIndex(const float *_p,bool &newPos) // get index for a vector float |
2985 | { |
2986 | uint32_t ret; |
2987 | |
2988 | if ( mUseDouble ) |
2989 | { |
2990 | double p[3]; |
2991 | p[0] = _p[0]; |
2992 | p[1] = _p[1]; |
2993 | p[2] = _p[2]; |
2994 | return getIndex(p,newPos); |
2995 | } |
2996 | |
2997 | newPos = false; |
2998 | |
2999 | float p[3]; |
3000 | |
3001 | if ( mSnapToGrid ) |
3002 | { |
3003 | p[0] = snapToGrid(_p[0]); |
3004 | p[1] = snapToGrid(_p[1]); |
3005 | p[2] = snapToGrid(_p[2]); |
3006 | } |
3007 | else |
3008 | { |
3009 | p[0] = _p[0]; |
3010 | p[1] = _p[1]; |
3011 | p[2] = _p[2]; |
3012 | } |
3013 | |
3014 | bool found; |
3015 | ret = mKdTree.getNearest(p,mFloatGranularity,found); |
3016 | if ( !found ) |
3017 | { |
3018 | newPos = true; |
3019 | ret = mKdTree.add(p[0],p[1],p[2]); |
3020 | } |
3021 | |
3022 | |
3023 | return ret; |
3024 | } |
3025 | |
3026 | uint32_t getIndex(const double *_p,bool &newPos) // get index for a vector double |
3027 | { |
3028 | uint32_t ret; |
3029 | |
3030 | if ( !mUseDouble ) |
3031 | { |
3032 | float p[3]; |
3033 | p[0] = (float)_p[0]; |
3034 | p[1] = (float)_p[1]; |
3035 | p[2] = (float)_p[2]; |
3036 | return getIndex(p,newPos); |
3037 | } |
3038 | |
3039 | newPos = false; |
3040 | |
3041 | double p[3]; |
3042 | |
3043 | if ( mSnapToGrid ) |
3044 | { |
3045 | p[0] = snapToGrid(_p[0]); |
3046 | p[1] = snapToGrid(_p[1]); |
3047 | p[2] = snapToGrid(_p[2]); |
3048 | } |
3049 | else |
3050 | { |
3051 | p[0] = _p[0]; |
3052 | p[1] = _p[1]; |
3053 | p[2] = _p[2]; |
3054 | } |
3055 | |
3056 | bool found; |
3057 | ret = mKdTree.getNearest(p,mDoubleGranularity,found); |
3058 | if ( !found ) |
3059 | { |
3060 | newPos = true; |
3061 | ret = mKdTree.add(p[0],p[1],p[2]); |
3062 | } |
3063 | |
3064 | |
3065 | return ret; |
3066 | } |
3067 | |
3068 | const float * getVerticesFloat(void) const |
3069 | { |
3070 | const float * ret = 0; |
3071 | |
3072 | assert( !mUseDouble ); |
3073 | |
3074 | ret = mKdTree.getVerticesFloat(); |
3075 | |
3076 | return ret; |
3077 | } |
3078 | |
3079 | const double * getVerticesDouble(void) const |
3080 | { |
3081 | const double * ret = 0; |
3082 | |
3083 | assert( mUseDouble ); |
3084 | |
3085 | ret = mKdTree.getVerticesDouble(); |
3086 | |
3087 | return ret; |
3088 | } |
3089 | |
3090 | const float * getVertexFloat(uint32_t index) const |
3091 | { |
3092 | const float * ret = 0; |
3093 | assert( !mUseDouble ); |
3094 | #ifdef _DEBUG |
3095 | uint32_t vcount = mKdTree.getVcount(); |
3096 | assert( index < vcount ); |
3097 | #endif |
3098 | ret = mKdTree.getVerticesFloat(); |
3099 | ret = &ret[index*3]; |
3100 | return ret; |
3101 | } |
3102 | |
3103 | const double * getVertexDouble(uint32_t index) const |
3104 | { |
3105 | const double * ret = 0; |
3106 | assert( mUseDouble ); |
3107 | #ifdef _DEBUG |
3108 | uint32_t vcount = mKdTree.getVcount(); |
3109 | assert( index < vcount ); |
3110 | #endif |
3111 | ret = mKdTree.getVerticesDouble(); |
3112 | ret = &ret[index*3]; |
3113 | |
3114 | return ret; |
3115 | } |
3116 | |
3117 | uint32_t getVcount(void) const |
3118 | { |
3119 | return mKdTree.getVcount(); |
3120 | } |
3121 | |
3122 | bool isDouble(void) const |
3123 | { |
3124 | return mUseDouble; |
3125 | } |
3126 | |
3127 | |
3128 | bool saveAsObj(const char *fname,uint32_t tcount,uint32_t *indices) |
3129 | { |
3130 | bool ret = false; |
3131 | |
3132 | |
3133 | FILE *fph = fopen(fname,"wb" ); |
3134 | if ( fph ) |
3135 | { |
3136 | ret = true; |
3137 | |
3138 | uint32_t vcount = getVcount(); |
3139 | if ( mUseDouble ) |
3140 | { |
3141 | const double *v = getVerticesDouble(); |
3142 | for (uint32_t i=0; i<vcount; i++) |
3143 | { |
3144 | fprintf(fph,"v %0.9f %0.9f %0.9f\r\n" , (float)v[0], (float)v[1], (float)v[2] ); |
3145 | v+=3; |
3146 | } |
3147 | } |
3148 | else |
3149 | { |
3150 | const float *v = getVerticesFloat(); |
3151 | for (uint32_t i=0; i<vcount; i++) |
3152 | { |
3153 | fprintf(fph,"v %0.9f %0.9f %0.9f\r\n" , v[0], v[1], v[2] ); |
3154 | v+=3; |
3155 | } |
3156 | } |
3157 | |
3158 | for (uint32_t i=0; i<tcount; i++) |
3159 | { |
3160 | uint32_t i1 = *indices++; |
3161 | uint32_t i2 = *indices++; |
3162 | uint32_t i3 = *indices++; |
3163 | fprintf(fph,"f %d %d %d\r\n" , i1+1, i2+1, i3+1 ); |
3164 | } |
3165 | fclose(fph); |
3166 | } |
3167 | |
3168 | return ret; |
3169 | } |
3170 | |
3171 | private: |
3172 | bool mUseDouble:1; |
3173 | bool mSnapToGrid:1; |
3174 | double mDoubleGranularity; |
3175 | float mFloatGranularity; |
3176 | VERTEX_INDEX::KdTree mKdTree; |
3177 | }; |
3178 | |
3179 | fm_VertexIndex * fm_createVertexIndex(double granularity,bool snapToGrid) // create an indexed vertex system for doubles |
3180 | { |
3181 | MyVertexIndex *ret = new MyVertexIndex(granularity,snapToGrid); |
3182 | return static_cast< fm_VertexIndex *>(ret); |
3183 | } |
3184 | |
3185 | fm_VertexIndex * fm_createVertexIndex(float granularity,bool snapToGrid) // create an indexed vertext system for floats |
3186 | { |
3187 | MyVertexIndex *ret = new MyVertexIndex(granularity,snapToGrid); |
3188 | return static_cast< fm_VertexIndex *>(ret); |
3189 | } |
3190 | |
3191 | void fm_releaseVertexIndex(fm_VertexIndex *vindex) |
3192 | { |
3193 | MyVertexIndex *m = static_cast< MyVertexIndex *>(vindex); |
3194 | delete m; |
3195 | } |
3196 | |
3197 | #endif // END OF VERTEX WELDING CODE |
3198 | |
3199 | |
3200 | REAL fm_computeBestFitAABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *bmin,REAL *bmax) // returns the diagonal distance |
3201 | { |
3202 | |
3203 | const uint8_t *source = (const uint8_t *) points; |
3204 | |
3205 | bmin[0] = points[0]; |
3206 | bmin[1] = points[1]; |
3207 | bmin[2] = points[2]; |
3208 | |
3209 | bmax[0] = points[0]; |
3210 | bmax[1] = points[1]; |
3211 | bmax[2] = points[2]; |
3212 | |
3213 | |
3214 | for (uint32_t i=1; i<vcount; i++) |
3215 | { |
3216 | source+=pstride; |
3217 | const REAL *p = (const REAL *) source; |
3218 | |
3219 | if ( p[0] < bmin[0] ) bmin[0] = p[0]; |
3220 | if ( p[1] < bmin[1] ) bmin[1] = p[1]; |
3221 | if ( p[2] < bmin[2] ) bmin[2] = p[2]; |
3222 | |
3223 | if ( p[0] > bmax[0] ) bmax[0] = p[0]; |
3224 | if ( p[1] > bmax[1] ) bmax[1] = p[1]; |
3225 | if ( p[2] > bmax[2] ) bmax[2] = p[2]; |
3226 | |
3227 | } |
3228 | |
3229 | REAL dx = bmax[0] - bmin[0]; |
3230 | REAL dy = bmax[1] - bmin[1]; |
3231 | REAL dz = bmax[2] - bmin[2]; |
3232 | |
3233 | return (REAL) sqrt( dx*dx + dy*dy + dz*dz ); |
3234 | |
3235 | } |
3236 | |
3237 | |
3238 | |
3239 | /* a = b - c */ |
3240 | #define vector(a,b,c) \ |
3241 | (a)[0] = (b)[0] - (c)[0]; \ |
3242 | (a)[1] = (b)[1] - (c)[1]; \ |
3243 | (a)[2] = (b)[2] - (c)[2]; |
3244 | |
3245 | |
3246 | |
3247 | #define innerProduct(v,q) \ |
3248 | ((v)[0] * (q)[0] + \ |
3249 | (v)[1] * (q)[1] + \ |
3250 | (v)[2] * (q)[2]) |
3251 | |
3252 | #define crossProduct(a,b,c) \ |
3253 | (a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \ |
3254 | (a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \ |
3255 | (a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1]; |
3256 | |
3257 | |
3258 | bool fm_lineIntersectsTriangle(const REAL *rayStart,const REAL *rayEnd,const REAL *p1,const REAL *p2,const REAL *p3,REAL *sect) |
3259 | { |
3260 | REAL dir[3]; |
3261 | |
3262 | dir[0] = rayEnd[0] - rayStart[0]; |
3263 | dir[1] = rayEnd[1] - rayStart[1]; |
3264 | dir[2] = rayEnd[2] - rayStart[2]; |
3265 | |
3266 | REAL d = (REAL)sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); |
3267 | REAL r = 1.0f / d; |
3268 | |
3269 | dir[0]*=r; |
3270 | dir[1]*=r; |
3271 | dir[2]*=r; |
3272 | |
3273 | |
3274 | REAL t; |
3275 | |
3276 | bool ret = fm_rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t ); |
3277 | |
3278 | if ( ret ) |
3279 | { |
3280 | if ( t > d ) |
3281 | { |
3282 | sect[0] = rayStart[0] + dir[0]*t; |
3283 | sect[1] = rayStart[1] + dir[1]*t; |
3284 | sect[2] = rayStart[2] + dir[2]*t; |
3285 | } |
3286 | else |
3287 | { |
3288 | ret = false; |
3289 | } |
3290 | } |
3291 | |
3292 | return ret; |
3293 | } |
3294 | |
3295 | |
3296 | |
3297 | bool fm_rayIntersectsTriangle(const REAL *p,const REAL *d,const REAL *v0,const REAL *v1,const REAL *v2,REAL &t) |
3298 | { |
3299 | REAL e1[3],e2[3],h[3],s[3],q[3]; |
3300 | REAL a,f,u,v; |
3301 | |
3302 | vector(e1,v1,v0); |
3303 | vector(e2,v2,v0); |
3304 | crossProduct(h,d,e2); |
3305 | a = innerProduct(e1,h); |
3306 | |
3307 | if (a > -0.00001 && a < 0.00001) |
3308 | return(false); |
3309 | |
3310 | f = 1/a; |
3311 | vector(s,p,v0); |
3312 | u = f * (innerProduct(s,h)); |
3313 | |
3314 | if (u < 0.0 || u > 1.0) |
3315 | return(false); |
3316 | |
3317 | crossProduct(q,s,e1); |
3318 | v = f * innerProduct(d,q); |
3319 | if (v < 0.0 || u + v > 1.0) |
3320 | return(false); |
3321 | // at this stage we can compute t to find out where |
3322 | // the intersection point is on the line |
3323 | t = f * innerProduct(e2,q); |
3324 | if (t > 0) // ray intersection |
3325 | return(true); |
3326 | else // this means that there is a line intersection |
3327 | // but not a ray intersection |
3328 | return (false); |
3329 | } |
3330 | |
3331 | |
3332 | inline REAL det(const REAL *p1,const REAL *p2,const REAL *p3) |
3333 | { |
3334 | return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2]; |
3335 | } |
3336 | |
3337 | |
3338 | REAL fm_computeMeshVolume(const REAL *vertices,uint32_t tcount,const uint32_t *indices) |
3339 | { |
3340 | REAL volume = 0; |
3341 | |
3342 | for (uint32_t i=0; i<tcount; i++,indices+=3) |
3343 | { |
3344 | const REAL *p1 = &vertices[ indices[0]*3 ]; |
3345 | const REAL *p2 = &vertices[ indices[1]*3 ]; |
3346 | const REAL *p3 = &vertices[ indices[2]*3 ]; |
3347 | volume+=det(p1,p2,p3); // compute the volume of the tetrahedran relative to the origin. |
3348 | } |
3349 | |
3350 | volume*=(1.0f/6.0f); |
3351 | if ( volume < 0 ) |
3352 | volume*=-1; |
3353 | return volume; |
3354 | } |
3355 | |
3356 | |
3357 | const REAL * fm_getPoint(const REAL *points,uint32_t pstride,uint32_t index) |
3358 | { |
3359 | const uint8_t *scan = (const uint8_t *)points; |
3360 | scan+=(index*pstride); |
3361 | return (REAL *)scan; |
3362 | } |
3363 | |
3364 | |
3365 | bool fm_insideTriangle(REAL Ax, REAL Ay, |
3366 | REAL Bx, REAL By, |
3367 | REAL Cx, REAL Cy, |
3368 | REAL Px, REAL Py) |
3369 | |
3370 | { |
3371 | REAL ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; |
3372 | REAL cCROSSap, bCROSScp, aCROSSbp; |
3373 | |
3374 | ax = Cx - Bx; ay = Cy - By; |
3375 | bx = Ax - Cx; by = Ay - Cy; |
3376 | cx = Bx - Ax; cy = By - Ay; |
3377 | apx= Px - Ax; apy= Py - Ay; |
3378 | bpx= Px - Bx; bpy= Py - By; |
3379 | cpx= Px - Cx; cpy= Py - Cy; |
3380 | |
3381 | aCROSSbp = ax*bpy - ay*bpx; |
3382 | cCROSSap = cx*apy - cy*apx; |
3383 | bCROSScp = bx*cpy - by*cpx; |
3384 | |
3385 | return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); |
3386 | } |
3387 | |
3388 | |
3389 | REAL fm_areaPolygon2d(uint32_t pcount,const REAL *points,uint32_t pstride) |
3390 | { |
3391 | int32_t n = (int32_t)pcount; |
3392 | |
3393 | REAL A=0.0f; |
3394 | for(int32_t p=n-1,q=0; q<n; p=q++) |
3395 | { |
3396 | const REAL *p1 = fm_getPoint(points,pstride,p); |
3397 | const REAL *p2 = fm_getPoint(points,pstride,q); |
3398 | A+= p1[0]*p2[1] - p2[0]*p1[1]; |
3399 | } |
3400 | return A*0.5f; |
3401 | } |
3402 | |
3403 | |
3404 | bool fm_pointInsidePolygon2d(uint32_t pcount,const REAL *points,uint32_t pstride,const REAL *point,uint32_t xindex,uint32_t yindex) |
3405 | { |
3406 | uint32_t j = pcount-1; |
3407 | int32_t oddNodes = 0; |
3408 | |
3409 | REAL x = point[xindex]; |
3410 | REAL y = point[yindex]; |
3411 | |
3412 | for (uint32_t i=0; i<pcount; i++) |
3413 | { |
3414 | const REAL *p1 = fm_getPoint(points,pstride,i); |
3415 | const REAL *p2 = fm_getPoint(points,pstride,j); |
3416 | |
3417 | REAL x1 = p1[xindex]; |
3418 | REAL y1 = p1[yindex]; |
3419 | |
3420 | REAL x2 = p2[xindex]; |
3421 | REAL y2 = p2[yindex]; |
3422 | |
3423 | if ( (y1 < y && y2 >= y) || (y2 < y && y1 >= y) ) |
3424 | { |
3425 | if (x1+(y-y1)/(y2-y1)*(x2-x1)<x) |
3426 | { |
3427 | oddNodes = 1-oddNodes; |
3428 | } |
3429 | } |
3430 | j = i; |
3431 | } |
3432 | |
3433 | return oddNodes ? true : false; |
3434 | } |
3435 | |
3436 | |
3437 | uint32_t fm_consolidatePolygon(uint32_t pcount,const REAL *points,uint32_t pstride,REAL *_dest,REAL epsilon) // collapses co-linear edges. |
3438 | { |
3439 | uint32_t ret = 0; |
3440 | |
3441 | |
3442 | if ( pcount >= 3 ) |
3443 | { |
3444 | const REAL *prev = fm_getPoint(points,pstride,pcount-1); |
3445 | const REAL *current = points; |
3446 | const REAL *next = fm_getPoint(points,pstride,1); |
3447 | REAL *dest = _dest; |
3448 | |
3449 | for (uint32_t i=0; i<pcount; i++) |
3450 | { |
3451 | |
3452 | next = (i+1)==pcount ? points : next; |
3453 | |
3454 | if ( !fm_colinear(prev,current,next,epsilon) ) |
3455 | { |
3456 | dest[0] = current[0]; |
3457 | dest[1] = current[1]; |
3458 | dest[2] = current[2]; |
3459 | |
3460 | dest+=3; |
3461 | ret++; |
3462 | } |
3463 | |
3464 | prev = current; |
3465 | current+=3; |
3466 | next+=3; |
3467 | |
3468 | } |
3469 | } |
3470 | |
3471 | return ret; |
3472 | } |
3473 | |
3474 | |
3475 | #ifndef RECT3D_TEMPLATE |
3476 | |
3477 | #define RECT3D_TEMPLATE |
3478 | |
3479 | template <class T> class Rect3d |
3480 | { |
3481 | public: |
3482 | Rect3d(void) { }; |
3483 | |
3484 | Rect3d(const T *bmin,const T *bmax) |
3485 | { |
3486 | |
3487 | mMin[0] = bmin[0]; |
3488 | mMin[1] = bmin[1]; |
3489 | mMin[2] = bmin[2]; |
3490 | |
3491 | mMax[0] = bmax[0]; |
3492 | mMax[1] = bmax[1]; |
3493 | mMax[2] = bmax[2]; |
3494 | |
3495 | } |
3496 | |
3497 | void SetMin(const T *bmin) |
3498 | { |
3499 | mMin[0] = bmin[0]; |
3500 | mMin[1] = bmin[1]; |
3501 | mMin[2] = bmin[2]; |
3502 | } |
3503 | |
3504 | void SetMax(const T *bmax) |
3505 | { |
3506 | mMax[0] = bmax[0]; |
3507 | mMax[1] = bmax[1]; |
3508 | mMax[2] = bmax[2]; |
3509 | } |
3510 | |
3511 | void SetMin(T x,T y,T z) |
3512 | { |
3513 | mMin[0] = x; |
3514 | mMin[1] = y; |
3515 | mMin[2] = z; |
3516 | } |
3517 | |
3518 | void SetMax(T x,T y,T z) |
3519 | { |
3520 | mMax[0] = x; |
3521 | mMax[1] = y; |
3522 | mMax[2] = z; |
3523 | } |
3524 | |
3525 | T mMin[3]; |
3526 | T mMax[3]; |
3527 | }; |
3528 | |
3529 | #endif |
3530 | |
3531 | void splitRect(uint32_t axis, |
3532 | const Rect3d<REAL> &source, |
3533 | Rect3d<REAL> &b1, |
3534 | Rect3d<REAL> &b2, |
3535 | const REAL *midpoint) |
3536 | { |
3537 | switch ( axis ) |
3538 | { |
3539 | case 0: |
3540 | b1.SetMin(source.mMin); |
3541 | b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] ); |
3542 | |
3543 | b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] ); |
3544 | b2.SetMax(source.mMax); |
3545 | |
3546 | break; |
3547 | case 1: |
3548 | b1.SetMin(source.mMin); |
3549 | b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] ); |
3550 | |
3551 | b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] ); |
3552 | b2.SetMax(source.mMax); |
3553 | |
3554 | break; |
3555 | case 2: |
3556 | b1.SetMin(source.mMin); |
3557 | b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] ); |
3558 | |
3559 | b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] ); |
3560 | b2.SetMax(source.mMax); |
3561 | |
3562 | break; |
3563 | } |
3564 | } |
3565 | |
3566 | bool fm_computeSplitPlane(uint32_t vcount, |
3567 | const REAL *vertices, |
3568 | uint32_t /* tcount */, |
3569 | const uint32_t * /* indices */, |
3570 | REAL *plane) |
3571 | { |
3572 | |
3573 | REAL sides[3]; |
3574 | REAL matrix[16]; |
3575 | |
3576 | fm_computeBestFitOBB( vcount, vertices, sizeof(REAL)*3, sides, matrix ); |
3577 | |
3578 | REAL bmax[3]; |
3579 | REAL bmin[3]; |
3580 | |
3581 | bmax[0] = sides[0]*0.5f; |
3582 | bmax[1] = sides[1]*0.5f; |
3583 | bmax[2] = sides[2]*0.5f; |
3584 | |
3585 | bmin[0] = -bmax[0]; |
3586 | bmin[1] = -bmax[1]; |
3587 | bmin[2] = -bmax[2]; |
3588 | |
3589 | |
3590 | REAL dx = sides[0]; |
3591 | REAL dy = sides[1]; |
3592 | REAL dz = sides[2]; |
3593 | |
3594 | |
3595 | uint32_t axis = 0; |
3596 | |
3597 | if ( dy > dx ) |
3598 | { |
3599 | axis = 1; |
3600 | } |
3601 | |
3602 | if ( dz > dx && dz > dy ) |
3603 | { |
3604 | axis = 2; |
3605 | } |
3606 | |
3607 | REAL p1[3]; |
3608 | REAL p2[3]; |
3609 | REAL p3[3]; |
3610 | |
3611 | p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f; |
3612 | p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f; |
3613 | p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f; |
3614 | |
3615 | Rect3d<REAL> b(bmin,bmax); |
3616 | |
3617 | Rect3d<REAL> b1,b2; |
3618 | |
3619 | splitRect(axis,b,b1,b2,p1); |
3620 | |
3621 | |
3622 | switch ( axis ) |
3623 | { |
3624 | case 0: |
3625 | p2[1] = bmin[1]; |
3626 | p2[2] = bmin[2]; |
3627 | |
3628 | if ( dz > dy ) |
3629 | { |
3630 | p3[1] = bmax[1]; |
3631 | p3[2] = bmin[2]; |
3632 | } |
3633 | else |
3634 | { |
3635 | p3[1] = bmin[1]; |
3636 | p3[2] = bmax[2]; |
3637 | } |
3638 | |
3639 | break; |
3640 | case 1: |
3641 | p2[0] = bmin[0]; |
3642 | p2[2] = bmin[2]; |
3643 | |
3644 | if ( dx > dz ) |
3645 | { |
3646 | p3[0] = bmax[0]; |
3647 | p3[2] = bmin[2]; |
3648 | } |
3649 | else |
3650 | { |
3651 | p3[0] = bmin[0]; |
3652 | p3[2] = bmax[2]; |
3653 | } |
3654 | |
3655 | break; |
3656 | case 2: |
3657 | p2[0] = bmin[0]; |
3658 | p2[1] = bmin[1]; |
3659 | |
3660 | if ( dx > dy ) |
3661 | { |
3662 | p3[0] = bmax[0]; |
3663 | p3[1] = bmin[1]; |
3664 | } |
3665 | else |
3666 | { |
3667 | p3[0] = bmin[0]; |
3668 | p3[1] = bmax[1]; |
3669 | } |
3670 | |
3671 | break; |
3672 | } |
3673 | |
3674 | REAL tp1[3]; |
3675 | REAL tp2[3]; |
3676 | REAL tp3[3]; |
3677 | |
3678 | fm_transform(matrix,p1,tp1); |
3679 | fm_transform(matrix,p2,tp2); |
3680 | fm_transform(matrix,p3,tp3); |
3681 | |
3682 | plane[3] = fm_computePlane(tp1,tp2,tp3,plane); |
3683 | |
3684 | return true; |
3685 | |
3686 | } |
3687 | |
3688 | #pragma warning(disable:4100) |
3689 | |
3690 | void fm_nearestPointInTriangle(const REAL * /*nearestPoint*/,const REAL * /*p1*/,const REAL * /*p2*/,const REAL * /*p3*/,REAL * /*nearest*/) |
3691 | { |
3692 | |
3693 | } |
3694 | |
3695 | static REAL Partial(const REAL *a,const REAL *p) |
3696 | { |
3697 | return (a[0]*p[1]) - (p[0]*a[1]); |
3698 | } |
3699 | |
3700 | REAL fm_areaTriangle(const REAL *p0,const REAL *p1,const REAL *p2) |
3701 | { |
3702 | REAL A = Partial(p0,p1); |
3703 | A+= Partial(p1,p2); |
3704 | A+= Partial(p2,p0); |
3705 | return A*0.5f; |
3706 | } |
3707 | |
3708 | void fm_subtract(const REAL *A,const REAL *B,REAL *diff) // compute A-B and store the result in 'diff' |
3709 | { |
3710 | diff[0] = A[0]-B[0]; |
3711 | diff[1] = A[1]-B[1]; |
3712 | diff[2] = A[2]-B[2]; |
3713 | } |
3714 | |
3715 | |
3716 | void fm_multiplyTransform(const REAL *pA,const REAL *pB,REAL *pM) |
3717 | { |
3718 | |
3719 | REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; |
3720 | REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; |
3721 | REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; |
3722 | REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; |
3723 | |
3724 | REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; |
3725 | REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; |
3726 | REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; |
3727 | REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; |
3728 | |
3729 | REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; |
3730 | REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; |
3731 | REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; |
3732 | REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; |
3733 | |
3734 | REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; |
3735 | REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; |
3736 | REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; |
3737 | REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; |
3738 | |
3739 | pM[0] = a; pM[1] = b; pM[2] = c; pM[3] = d; |
3740 | |
3741 | pM[4] = e; pM[5] = f; pM[6] = g; pM[7] = h; |
3742 | |
3743 | pM[8] = i; pM[9] = j; pM[10] = k; pM[11] = l; |
3744 | |
3745 | pM[12] = m; pM[13] = n; pM[14] = o; pM[15] = p; |
3746 | } |
3747 | |
3748 | void fm_multiply(REAL *A,REAL scaler) |
3749 | { |
3750 | A[0]*=scaler; |
3751 | A[1]*=scaler; |
3752 | A[2]*=scaler; |
3753 | } |
3754 | |
3755 | void fm_add(const REAL *A,const REAL *B,REAL *sum) |
3756 | { |
3757 | sum[0] = A[0]+B[0]; |
3758 | sum[1] = A[1]+B[1]; |
3759 | sum[2] = A[2]+B[2]; |
3760 | } |
3761 | |
3762 | void fm_copy3(const REAL *source,REAL *dest) |
3763 | { |
3764 | dest[0] = source[0]; |
3765 | dest[1] = source[1]; |
3766 | dest[2] = source[2]; |
3767 | } |
3768 | |
3769 | |
3770 | uint32_t fm_copyUniqueVertices(uint32_t vcount,const REAL *input_vertices,REAL *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices) |
3771 | { |
3772 | uint32_t ret = 0; |
3773 | |
3774 | REAL *vertices = (REAL *)malloc(sizeof(REAL)*vcount*3); |
3775 | memcpy(vertices,input_vertices,sizeof(REAL)*vcount*3); |
3776 | REAL *dest = output_vertices; |
3777 | |
3778 | uint32_t *reindex = (uint32_t *)malloc(sizeof(uint32_t)*vcount); |
3779 | memset(reindex,0xFF,sizeof(uint32_t)*vcount); |
3780 | |
3781 | uint32_t icount = tcount*3; |
3782 | |
3783 | for (uint32_t i=0; i<icount; i++) |
3784 | { |
3785 | uint32_t index = *input_indices++; |
3786 | |
3787 | assert( index < vcount ); |
3788 | |
3789 | if ( reindex[index] == 0xFFFFFFFF ) |
3790 | { |
3791 | *output_indices++ = ret; |
3792 | reindex[index] = ret; |
3793 | const REAL *pos = &vertices[index*3]; |
3794 | dest[0] = pos[0]; |
3795 | dest[1] = pos[1]; |
3796 | dest[2] = pos[2]; |
3797 | dest+=3; |
3798 | ret++; |
3799 | } |
3800 | else |
3801 | { |
3802 | *output_indices++ = reindex[index]; |
3803 | } |
3804 | } |
3805 | free(vertices); |
3806 | free(reindex); |
3807 | return ret; |
3808 | } |
3809 | |
3810 | bool fm_isMeshCoplanar(uint32_t tcount,const uint32_t *indices,const REAL *vertices,bool doubleSided) // returns true if this collection of indexed triangles are co-planar! |
3811 | { |
3812 | bool ret = true; |
3813 | |
3814 | if ( tcount > 0 ) |
3815 | { |
3816 | uint32_t i1 = indices[0]; |
3817 | uint32_t i2 = indices[1]; |
3818 | uint32_t i3 = indices[2]; |
3819 | const REAL *p1 = &vertices[i1*3]; |
3820 | const REAL *p2 = &vertices[i2*3]; |
3821 | const REAL *p3 = &vertices[i3*3]; |
3822 | REAL plane[4]; |
3823 | plane[3] = fm_computePlane(p1,p2,p3,plane); |
3824 | const uint32_t *scan = &indices[3]; |
3825 | for (uint32_t i=1; i<tcount; i++) |
3826 | { |
3827 | i1 = *scan++; |
3828 | i2 = *scan++; |
3829 | i3 = *scan++; |
3830 | p1 = &vertices[i1*3]; |
3831 | p2 = &vertices[i2*3]; |
3832 | p3 = &vertices[i3*3]; |
3833 | REAL _plane[4]; |
3834 | _plane[3] = fm_computePlane(p1,p2,p3,_plane); |
3835 | if ( !fm_samePlane(plane,_plane,0.01f,0.001f,doubleSided) ) |
3836 | { |
3837 | ret = false; |
3838 | break; |
3839 | } |
3840 | } |
3841 | } |
3842 | return ret; |
3843 | } |
3844 | |
3845 | |
3846 | bool fm_samePlane(const REAL p1[4],const REAL p2[4],REAL normalEpsilon,REAL dEpsilon,bool doubleSided) |
3847 | { |
3848 | bool ret = false; |
3849 | |
3850 | #if 0 |
3851 | if (p1[0] == p2[0] && |
3852 | p1[1] == p2[1] && |
3853 | p1[2] == p2[2] && |
3854 | p1[3] == p2[3]) |
3855 | { |
3856 | ret = true; |
3857 | } |
3858 | #else |
3859 | REAL diff = (REAL) fabs(p1[3]-p2[3]); |
3860 | if ( diff < dEpsilon ) // if the plane -d co-efficient is within our epsilon |
3861 | { |
3862 | REAL dot = fm_dot(p1,p2); // compute the dot-product of the vector normals. |
3863 | if ( doubleSided ) dot = (REAL)fabs(dot); |
3864 | REAL dmin = 1 - normalEpsilon; |
3865 | REAL dmax = 1 + normalEpsilon; |
3866 | if ( dot >= dmin && dot <= dmax ) |
3867 | { |
3868 | ret = true; // then the plane equation is for practical purposes identical. |
3869 | } |
3870 | } |
3871 | #endif |
3872 | return ret; |
3873 | } |
3874 | |
3875 | |
3876 | void fm_initMinMax(REAL bmin[3],REAL bmax[3]) |
3877 | { |
3878 | bmin[0] = FLT_MAX; |
3879 | bmin[1] = FLT_MAX; |
3880 | bmin[2] = FLT_MAX; |
3881 | |
3882 | bmax[0] = -FLT_MAX; |
3883 | bmax[1] = -FLT_MAX; |
3884 | bmax[2] = -FLT_MAX; |
3885 | } |
3886 | |
3887 | void fm_inflateMinMax(REAL bmin[3], REAL bmax[3], REAL ratio) |
3888 | { |
3889 | REAL inflate = fm_distance(bmin, bmax)*0.5f*ratio; |
3890 | |
3891 | bmin[0] -= inflate; |
3892 | bmin[1] -= inflate; |
3893 | bmin[2] -= inflate; |
3894 | |
3895 | bmax[0] += inflate; |
3896 | bmax[1] += inflate; |
3897 | bmax[2] += inflate; |
3898 | } |
3899 | |
3900 | #ifndef TESSELATE_H |
3901 | |
3902 | #define TESSELATE_H |
3903 | |
3904 | typedef std::vector< uint32_t > UintVector; |
3905 | |
3906 | class Myfm_Tesselate : public fm_Tesselate |
3907 | { |
3908 | public: |
3909 | virtual ~Myfm_Tesselate(void) |
3910 | { |
3911 | |
3912 | } |
3913 | |
3914 | const uint32_t * tesselate(fm_VertexIndex *vindex,uint32_t tcount,const uint32_t *indices,float longEdge,uint32_t maxDepth,uint32_t &outcount) |
3915 | { |
3916 | const uint32_t *ret = 0; |
3917 | |
3918 | mMaxDepth = maxDepth; |
3919 | mLongEdge = longEdge*longEdge; |
3920 | mLongEdgeD = mLongEdge; |
3921 | mVertices = vindex; |
3922 | |
3923 | if ( mVertices->isDouble() ) |
3924 | { |
3925 | uint32_t vcount = mVertices->getVcount(); |
3926 | double *vertices = (double *)malloc(sizeof(double)*vcount*3); |
3927 | memcpy(vertices,mVertices->getVerticesDouble(),sizeof(double)*vcount*3); |
3928 | |
3929 | for (uint32_t i=0; i<tcount; i++) |
3930 | { |
3931 | uint32_t i1 = *indices++; |
3932 | uint32_t i2 = *indices++; |
3933 | uint32_t i3 = *indices++; |
3934 | |
3935 | const double *p1 = &vertices[i1*3]; |
3936 | const double *p2 = &vertices[i2*3]; |
3937 | const double *p3 = &vertices[i3*3]; |
3938 | |
3939 | tesselate(p1,p2,p3,0); |
3940 | |
3941 | } |
3942 | free(vertices); |
3943 | } |
3944 | else |
3945 | { |
3946 | uint32_t vcount = mVertices->getVcount(); |
3947 | float *vertices = (float *)malloc(sizeof(float)*vcount*3); |
3948 | memcpy(vertices,mVertices->getVerticesFloat(),sizeof(float)*vcount*3); |
3949 | |
3950 | |
3951 | for (uint32_t i=0; i<tcount; i++) |
3952 | { |
3953 | uint32_t i1 = *indices++; |
3954 | uint32_t i2 = *indices++; |
3955 | uint32_t i3 = *indices++; |
3956 | |
3957 | const float *p1 = &vertices[i1*3]; |
3958 | const float *p2 = &vertices[i2*3]; |
3959 | const float *p3 = &vertices[i3*3]; |
3960 | |
3961 | tesselate(p1,p2,p3,0); |
3962 | |
3963 | } |
3964 | free(vertices); |
3965 | } |
3966 | |
3967 | outcount = (uint32_t)(mIndices.size()/3); |
3968 | ret = &mIndices[0]; |
3969 | |
3970 | |
3971 | return ret; |
3972 | } |
3973 | |
3974 | void tesselate(const float *p1,const float *p2,const float *p3,uint32_t recurse) |
3975 | { |
3976 | bool split = false; |
3977 | float l1,l2,l3; |
3978 | |
3979 | l1 = l2 = l3 = 0; |
3980 | |
3981 | if ( recurse < mMaxDepth ) |
3982 | { |
3983 | l1 = fm_distanceSquared(p1,p2); |
3984 | l2 = fm_distanceSquared(p2,p3); |
3985 | l3 = fm_distanceSquared(p3,p1); |
3986 | |
3987 | if ( l1 > mLongEdge || l2 > mLongEdge || l3 > mLongEdge ) |
3988 | split = true; |
3989 | |
3990 | } |
3991 | |
3992 | if ( split ) |
3993 | { |
3994 | uint32_t edge; |
3995 | |
3996 | if ( l1 >= l2 && l1 >= l3 ) |
3997 | edge = 0; |
3998 | else if ( l2 >= l1 && l2 >= l3 ) |
3999 | edge = 1; |
4000 | else |
4001 | edge = 2; |
4002 | |
4003 | float splits[3]; |
4004 | |
4005 | switch ( edge ) |
4006 | { |
4007 | case 0: |
4008 | { |
4009 | fm_lerp(p1,p2,splits,0.5f); |
4010 | tesselate(p1,splits,p3, recurse+1 ); |
4011 | tesselate(splits,p2,p3, recurse+1 ); |
4012 | } |
4013 | break; |
4014 | case 1: |
4015 | { |
4016 | fm_lerp(p2,p3,splits,0.5f); |
4017 | tesselate(p1,p2,splits, recurse+1 ); |
4018 | tesselate(p1,splits,p3, recurse+1 ); |
4019 | } |
4020 | break; |
4021 | case 2: |
4022 | { |
4023 | fm_lerp(p3,p1,splits,0.5f); |
4024 | tesselate(p1,p2,splits, recurse+1 ); |
4025 | tesselate(splits,p2,p3, recurse+1 ); |
4026 | } |
4027 | break; |
4028 | } |
4029 | } |
4030 | else |
4031 | { |
4032 | bool newp; |
4033 | |
4034 | uint32_t i1 = mVertices->getIndex(p1,newp); |
4035 | uint32_t i2 = mVertices->getIndex(p2,newp); |
4036 | uint32_t i3 = mVertices->getIndex(p3,newp); |
4037 | |
4038 | mIndices.push_back(i1); |
4039 | mIndices.push_back(i2); |
4040 | mIndices.push_back(i3); |
4041 | } |
4042 | |
4043 | } |
4044 | |
4045 | void tesselate(const double *p1,const double *p2,const double *p3,uint32_t recurse) |
4046 | { |
4047 | bool split = false; |
4048 | double l1,l2,l3; |
4049 | |
4050 | l1 = l2 = l3 = 0; |
4051 | |
4052 | if ( recurse < mMaxDepth ) |
4053 | { |
4054 | l1 = fm_distanceSquared(p1,p2); |
4055 | l2 = fm_distanceSquared(p2,p3); |
4056 | l3 = fm_distanceSquared(p3,p1); |
4057 | |
4058 | if ( l1 > mLongEdgeD || l2 > mLongEdgeD || l3 > mLongEdgeD ) |
4059 | split = true; |
4060 | |
4061 | } |
4062 | |
4063 | if ( split ) |
4064 | { |
4065 | uint32_t edge; |
4066 | |
4067 | if ( l1 >= l2 && l1 >= l3 ) |
4068 | edge = 0; |
4069 | else if ( l2 >= l1 && l2 >= l3 ) |
4070 | edge = 1; |
4071 | else |
4072 | edge = 2; |
4073 | |
4074 | double splits[3]; |
4075 | |
4076 | switch ( edge ) |
4077 | { |
4078 | case 0: |
4079 | { |
4080 | fm_lerp(p1,p2,splits,0.5); |
4081 | tesselate(p1,splits,p3, recurse+1 ); |
4082 | tesselate(splits,p2,p3, recurse+1 ); |
4083 | } |
4084 | break; |
4085 | case 1: |
4086 | { |
4087 | fm_lerp(p2,p3,splits,0.5); |
4088 | tesselate(p1,p2,splits, recurse+1 ); |
4089 | tesselate(p1,splits,p3, recurse+1 ); |
4090 | } |
4091 | break; |
4092 | case 2: |
4093 | { |
4094 | fm_lerp(p3,p1,splits,0.5); |
4095 | tesselate(p1,p2,splits, recurse+1 ); |
4096 | tesselate(splits,p2,p3, recurse+1 ); |
4097 | } |
4098 | break; |
4099 | } |
4100 | } |
4101 | else |
4102 | { |
4103 | bool newp; |
4104 | |
4105 | uint32_t i1 = mVertices->getIndex(p1,newp); |
4106 | uint32_t i2 = mVertices->getIndex(p2,newp); |
4107 | uint32_t i3 = mVertices->getIndex(p3,newp); |
4108 | |
4109 | mIndices.push_back(i1); |
4110 | mIndices.push_back(i2); |
4111 | mIndices.push_back(i3); |
4112 | } |
4113 | |
4114 | } |
4115 | |
4116 | private: |
4117 | float mLongEdge; |
4118 | double mLongEdgeD; |
4119 | fm_VertexIndex *mVertices; |
4120 | UintVector mIndices; |
4121 | uint32_t mMaxDepth; |
4122 | }; |
4123 | |
4124 | fm_Tesselate * fm_createTesselate(void) |
4125 | { |
4126 | Myfm_Tesselate *m = new Myfm_Tesselate; |
4127 | return static_cast< fm_Tesselate * >(m); |
4128 | } |
4129 | |
4130 | void fm_releaseTesselate(fm_Tesselate *t) |
4131 | { |
4132 | Myfm_Tesselate *m = static_cast< Myfm_Tesselate *>(t); |
4133 | delete m; |
4134 | } |
4135 | |
4136 | #endif |
4137 | |
4138 | |
4139 | #ifndef RAY_ABB_INTERSECT |
4140 | |
4141 | #define RAY_ABB_INTERSECT |
4142 | |
4143 | //! Integer representation of a floating-point value. |
4144 | #define IR(x) ((uint32_t&)x) |
4145 | |
4146 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
4147 | /** |
4148 | * A method to compute a ray-AABB intersection. |
4149 | * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 |
4150 | * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) |
4151 | * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) |
4152 | * |
4153 | * Hence this version is faster as well as more robust than the original one. |
4154 | * |
4155 | * Should work provided: |
4156 | * 1) the integer representation of 0.0f is 0x00000000 |
4157 | * 2) the sign bit of the float is the most significant one |
4158 | * |
4159 | * Report bugs: p.terdiman@codercorner.com |
4160 | * |
4161 | * \param aabb [in] the axis-aligned bounding box |
4162 | * \param origin [in] ray origin |
4163 | * \param dir [in] ray direction |
4164 | * \param coord [out] impact coordinates |
4165 | * \return true if ray intersects AABB |
4166 | */ |
4167 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
4168 | #define RAYAABB_EPSILON 0.00001f |
4169 | bool fm_intersectRayAABB(const float MinB[3],const float MaxB[3],const float origin[3],const float dir[3],float coord[3]) |
4170 | { |
4171 | bool Inside = true; |
4172 | float MaxT[3]; |
4173 | MaxT[0]=MaxT[1]=MaxT[2]=-1.0f; |
4174 | |
4175 | // Find candidate planes. |
4176 | for(uint32_t i=0;i<3;i++) |
4177 | { |
4178 | if(origin[i] < MinB[i]) |
4179 | { |
4180 | coord[i] = MinB[i]; |
4181 | Inside = false; |
4182 | |
4183 | // Calculate T distances to candidate planes |
4184 | if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i]; |
4185 | } |
4186 | else if(origin[i] > MaxB[i]) |
4187 | { |
4188 | coord[i] = MaxB[i]; |
4189 | Inside = false; |
4190 | |
4191 | // Calculate T distances to candidate planes |
4192 | if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i]; |
4193 | } |
4194 | } |
4195 | |
4196 | // Ray origin inside bounding box |
4197 | if(Inside) |
4198 | { |
4199 | coord[0] = origin[0]; |
4200 | coord[1] = origin[1]; |
4201 | coord[2] = origin[2]; |
4202 | return true; |
4203 | } |
4204 | |
4205 | // Get largest of the maxT's for final choice of intersection |
4206 | uint32_t WhichPlane = 0; |
4207 | if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; |
4208 | if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; |
4209 | |
4210 | // Check final candidate actually inside box |
4211 | if(IR(MaxT[WhichPlane])&0x80000000) return false; |
4212 | |
4213 | for(uint32_t i=0;i<3;i++) |
4214 | { |
4215 | if(i!=WhichPlane) |
4216 | { |
4217 | coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; |
4218 | #ifdef RAYAABB_EPSILON |
4219 | if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false; |
4220 | #else |
4221 | if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false; |
4222 | #endif |
4223 | } |
4224 | } |
4225 | return true; // ray hits box |
4226 | } |
4227 | |
4228 | bool fm_intersectLineSegmentAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],float intersect[3]) |
4229 | { |
4230 | bool ret = false; |
4231 | |
4232 | float dir[3]; |
4233 | dir[0] = p2[0] - p1[0]; |
4234 | dir[1] = p2[1] - p1[1]; |
4235 | dir[2] = p2[2] - p1[2]; |
4236 | float dist = fm_normalize(dir); |
4237 | if ( dist > RAYAABB_EPSILON ) |
4238 | { |
4239 | ret = fm_intersectRayAABB(bmin,bmax,p1,dir,intersect); |
4240 | if ( ret ) |
4241 | { |
4242 | float d = fm_distanceSquared(p1,intersect); |
4243 | if ( d > (dist*dist) ) |
4244 | { |
4245 | ret = false; |
4246 | } |
4247 | } |
4248 | } |
4249 | return ret; |
4250 | } |
4251 | |
4252 | #endif |
4253 | |
4254 | #ifndef OBB_TO_AABB |
4255 | |
4256 | #define OBB_TO_AABB |
4257 | |
4258 | #pragma warning(disable:4100) |
4259 | |
4260 | void fm_OBBtoAABB(const float /*obmin*/[3],const float /*obmax*/[3],const float /*matrix*/[16],float /*abmin*/[3],float /*abmax*/[3]) |
4261 | { |
4262 | assert(0); // not yet implemented. |
4263 | } |
4264 | |
4265 | |
4266 | const REAL * computePos(uint32_t index,const REAL *vertices,uint32_t vstride) |
4267 | { |
4268 | const char *tmp = (const char *)vertices; |
4269 | tmp+=(index*vstride); |
4270 | return (const REAL*)tmp; |
4271 | } |
4272 | |
4273 | void computeNormal(uint32_t index,REAL *normals,uint32_t nstride,const REAL *normal) |
4274 | { |
4275 | char *tmp = (char *)normals; |
4276 | tmp+=(index*nstride); |
4277 | REAL *dest = (REAL *)tmp; |
4278 | dest[0]+=normal[0]; |
4279 | dest[1]+=normal[1]; |
4280 | dest[2]+=normal[2]; |
4281 | } |
4282 | |
4283 | void fm_computeMeanNormals(uint32_t vcount, // the number of vertices |
4284 | const REAL *vertices, // the base address of the vertex position data. |
4285 | uint32_t vstride, // the stride between position data. |
4286 | REAL *normals, // the base address of the destination for mean vector normals |
4287 | uint32_t nstride, // the stride between normals |
4288 | uint32_t tcount, // the number of triangles |
4289 | const uint32_t *indices) // the triangle indices |
4290 | { |
4291 | |
4292 | // Step #1 : Zero out the vertex normals |
4293 | char *dest = (char *)normals; |
4294 | for (uint32_t i=0; i<vcount; i++) |
4295 | { |
4296 | REAL *n = (REAL *)dest; |
4297 | n[0] = 0; |
4298 | n[1] = 0; |
4299 | n[2] = 0; |
4300 | dest+=nstride; |
4301 | } |
4302 | |
4303 | // Step #2 : Compute the face normals and accumulate them |
4304 | const uint32_t *scan = indices; |
4305 | for (uint32_t i=0; i<tcount; i++) |
4306 | { |
4307 | |
4308 | uint32_t i1 = *scan++; |
4309 | uint32_t i2 = *scan++; |
4310 | uint32_t i3 = *scan++; |
4311 | |
4312 | const REAL *p1 = computePos(i1,vertices,vstride); |
4313 | const REAL *p2 = computePos(i2,vertices,vstride); |
4314 | const REAL *p3 = computePos(i3,vertices,vstride); |
4315 | |
4316 | REAL normal[3]; |
4317 | fm_computePlane(p3,p2,p1,normal); |
4318 | |
4319 | computeNormal(i1,normals,nstride,normal); |
4320 | computeNormal(i2,normals,nstride,normal); |
4321 | computeNormal(i3,normals,nstride,normal); |
4322 | } |
4323 | |
4324 | |
4325 | // Normalize the accumulated normals |
4326 | dest = (char *)normals; |
4327 | for (uint32_t i=0; i<vcount; i++) |
4328 | { |
4329 | REAL *n = (REAL *)dest; |
4330 | fm_normalize(n); |
4331 | dest+=nstride; |
4332 | } |
4333 | |
4334 | } |
4335 | |
4336 | #endif |
4337 | |
4338 | |
4339 | #define BIGNUMBER 100000000.0 /* hundred million */ |
4340 | |
4341 | static inline void Set(REAL *n,REAL x,REAL y,REAL z) |
4342 | { |
4343 | n[0] = x; |
4344 | n[1] = y; |
4345 | n[2] = z; |
4346 | }; |
4347 | |
4348 | static inline void Copy(REAL *dest,const REAL *source) |
4349 | { |
4350 | dest[0] = source[0]; |
4351 | dest[1] = source[1]; |
4352 | dest[2] = source[2]; |
4353 | } |
4354 | |
4355 | |
4356 | REAL fm_computeBestFitSphere(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *center) |
4357 | { |
4358 | REAL radius; |
4359 | REAL radius2; |
4360 | |
4361 | REAL xmin[3]; |
4362 | REAL xmax[3]; |
4363 | REAL ymin[3]; |
4364 | REAL ymax[3]; |
4365 | REAL zmin[3]; |
4366 | REAL zmax[3]; |
4367 | REAL dia1[3]; |
4368 | REAL dia2[3]; |
4369 | |
4370 | /* FIRST PASS: find 6 minima/maxima points */ |
4371 | Set(xmin,BIGNUMBER,BIGNUMBER,BIGNUMBER); |
4372 | Set(xmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); |
4373 | Set(ymin,BIGNUMBER,BIGNUMBER,BIGNUMBER); |
4374 | Set(ymax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); |
4375 | Set(zmin,BIGNUMBER,BIGNUMBER,BIGNUMBER); |
4376 | Set(zmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); |
4377 | |
4378 | { |
4379 | const char *scan = (const char *)points; |
4380 | for (uint32_t i=0; i<vcount; i++) |
4381 | { |
4382 | const REAL *caller_p = (const REAL *)scan; |
4383 | if (caller_p[0]<xmin[0]) |
4384 | Copy(xmin,caller_p); /* New xminimum point */ |
4385 | if (caller_p[0]>xmax[0]) |
4386 | Copy(xmax,caller_p); |
4387 | if (caller_p[1]<ymin[1]) |
4388 | Copy(ymin,caller_p); |
4389 | if (caller_p[1]>ymax[1]) |
4390 | Copy(ymax,caller_p); |
4391 | if (caller_p[2]<zmin[2]) |
4392 | Copy(zmin,caller_p); |
4393 | if (caller_p[2]>zmax[2]) |
4394 | Copy(zmax,caller_p); |
4395 | scan+=pstride; |
4396 | } |
4397 | } |
4398 | |
4399 | /* Set xspan = distance between the 2 points xmin & xmax (squared) */ |
4400 | REAL dx = xmax[0] - xmin[0]; |
4401 | REAL dy = xmax[1] - xmin[1]; |
4402 | REAL dz = xmax[2] - xmin[2]; |
4403 | REAL xspan = dx*dx + dy*dy + dz*dz; |
4404 | |
4405 | /* Same for y & z spans */ |
4406 | dx = ymax[0] - ymin[0]; |
4407 | dy = ymax[1] - ymin[1]; |
4408 | dz = ymax[2] - ymin[2]; |
4409 | REAL yspan = dx*dx + dy*dy + dz*dz; |
4410 | |
4411 | dx = zmax[0] - zmin[0]; |
4412 | dy = zmax[1] - zmin[1]; |
4413 | dz = zmax[2] - zmin[2]; |
4414 | REAL zspan = dx*dx + dy*dy + dz*dz; |
4415 | |
4416 | /* Set points dia1 & dia2 to the maximally separated pair */ |
4417 | Copy(dia1,xmin); |
4418 | Copy(dia2,xmax); /* assume xspan biggest */ |
4419 | REAL maxspan = xspan; |
4420 | |
4421 | if (yspan>maxspan) |
4422 | { |
4423 | maxspan = yspan; |
4424 | Copy(dia1,ymin); |
4425 | Copy(dia2,ymax); |
4426 | } |
4427 | |
4428 | if (zspan>maxspan) |
4429 | { |
4430 | maxspan = zspan; |
4431 | Copy(dia1,zmin); |
4432 | Copy(dia2,zmax); |
4433 | } |
4434 | |
4435 | |
4436 | /* dia1,dia2 is a diameter of initial sphere */ |
4437 | /* calc initial center */ |
4438 | center[0] = (dia1[0]+dia2[0])*0.5f; |
4439 | center[1] = (dia1[1]+dia2[1])*0.5f; |
4440 | center[2] = (dia1[2]+dia2[2])*0.5f; |
4441 | |
4442 | /* calculate initial radius**2 and radius */ |
4443 | |
4444 | dx = dia2[0]-center[0]; /* x component of radius vector */ |
4445 | dy = dia2[1]-center[1]; /* y component of radius vector */ |
4446 | dz = dia2[2]-center[2]; /* z component of radius vector */ |
4447 | |
4448 | radius2 = dx*dx + dy*dy + dz*dz; |
4449 | radius = REAL(sqrt(radius2)); |
4450 | |
4451 | /* SECOND PASS: increment current sphere */ |
4452 | { |
4453 | const char *scan = (const char *)points; |
4454 | for (uint32_t i=0; i<vcount; i++) |
4455 | { |
4456 | const REAL *caller_p = (const REAL *)scan; |
4457 | dx = caller_p[0]-center[0]; |
4458 | dy = caller_p[1]-center[1]; |
4459 | dz = caller_p[2]-center[2]; |
4460 | REAL old_to_p_sq = dx*dx + dy*dy + dz*dz; |
4461 | if (old_to_p_sq > radius2) /* do r**2 test first */ |
4462 | { /* this point is outside of current sphere */ |
4463 | REAL old_to_p = REAL(sqrt(old_to_p_sq)); |
4464 | /* calc radius of new sphere */ |
4465 | radius = (radius + old_to_p) * 0.5f; |
4466 | radius2 = radius*radius; /* for next r**2 compare */ |
4467 | REAL old_to_new = old_to_p - radius; |
4468 | /* calc center of new sphere */ |
4469 | REAL recip = 1.0f /old_to_p; |
4470 | REAL cx = (radius*center[0] + old_to_new*caller_p[0]) * recip; |
4471 | REAL cy = (radius*center[1] + old_to_new*caller_p[1]) * recip; |
4472 | REAL cz = (radius*center[2] + old_to_new*caller_p[2]) * recip; |
4473 | Set(center,cx,cy,cz); |
4474 | scan+=pstride; |
4475 | } |
4476 | } |
4477 | } |
4478 | return radius; |
4479 | } |
4480 | |
4481 | |
4482 | void fm_computeBestFitCapsule(uint32_t vcount,const REAL *points,uint32_t pstride,REAL &radius,REAL &height,REAL matrix[16],bool bruteForce) |
4483 | { |
4484 | REAL sides[3]; |
4485 | REAL omatrix[16]; |
4486 | fm_computeBestFitOBB(vcount,points,pstride,sides,omatrix,bruteForce); |
4487 | |
4488 | int32_t axis = 0; |
4489 | if ( sides[0] > sides[1] && sides[0] > sides[2] ) |
4490 | axis = 0; |
4491 | else if ( sides[1] > sides[0] && sides[1] > sides[2] ) |
4492 | axis = 1; |
4493 | else |
4494 | axis = 2; |
4495 | |
4496 | REAL localTransform[16]; |
4497 | |
4498 | REAL maxDist = 0; |
4499 | REAL maxLen = 0; |
4500 | |
4501 | switch ( axis ) |
4502 | { |
4503 | case 0: |
4504 | { |
4505 | fm_eulerMatrix(0,0,FM_PI/2,localTransform); |
4506 | fm_matrixMultiply(localTransform,omatrix,matrix); |
4507 | |
4508 | const uint8_t *scan = (const uint8_t *)points; |
4509 | for (uint32_t i=0; i<vcount; i++) |
4510 | { |
4511 | const REAL *p = (const REAL *)scan; |
4512 | REAL t[3]; |
4513 | fm_inverseRT(omatrix,p,t); |
4514 | REAL dist = t[1]*t[1]+t[2]*t[2]; |
4515 | if ( dist > maxDist ) |
4516 | { |
4517 | maxDist = dist; |
4518 | } |
4519 | REAL l = (REAL) fabs(t[0]); |
4520 | if ( l > maxLen ) |
4521 | { |
4522 | maxLen = l; |
4523 | } |
4524 | scan+=pstride; |
4525 | } |
4526 | } |
4527 | height = sides[0]; |
4528 | break; |
4529 | case 1: |
4530 | { |
4531 | fm_eulerMatrix(0,FM_PI/2,0,localTransform); |
4532 | fm_matrixMultiply(localTransform,omatrix,matrix); |
4533 | |
4534 | const uint8_t *scan = (const uint8_t *)points; |
4535 | for (uint32_t i=0; i<vcount; i++) |
4536 | { |
4537 | const REAL *p = (const REAL *)scan; |
4538 | REAL t[3]; |
4539 | fm_inverseRT(omatrix,p,t); |
4540 | REAL dist = t[0]*t[0]+t[2]*t[2]; |
4541 | if ( dist > maxDist ) |
4542 | { |
4543 | maxDist = dist; |
4544 | } |
4545 | REAL l = (REAL) fabs(t[1]); |
4546 | if ( l > maxLen ) |
4547 | { |
4548 | maxLen = l; |
4549 | } |
4550 | scan+=pstride; |
4551 | } |
4552 | } |
4553 | height = sides[1]; |
4554 | break; |
4555 | case 2: |
4556 | { |
4557 | fm_eulerMatrix(FM_PI/2,0,0,localTransform); |
4558 | fm_matrixMultiply(localTransform,omatrix,matrix); |
4559 | |
4560 | const uint8_t *scan = (const uint8_t *)points; |
4561 | for (uint32_t i=0; i<vcount; i++) |
4562 | { |
4563 | const REAL *p = (const REAL *)scan; |
4564 | REAL t[3]; |
4565 | fm_inverseRT(omatrix,p,t); |
4566 | REAL dist = t[0]*t[0]+t[1]*t[1]; |
4567 | if ( dist > maxDist ) |
4568 | { |
4569 | maxDist = dist; |
4570 | } |
4571 | REAL l = (REAL) fabs(t[2]); |
4572 | if ( l > maxLen ) |
4573 | { |
4574 | maxLen = l; |
4575 | } |
4576 | scan+=pstride; |
4577 | } |
4578 | } |
4579 | height = sides[2]; |
4580 | break; |
4581 | } |
4582 | radius = (REAL)sqrt(maxDist); |
4583 | height = (maxLen*2)-(radius*2); |
4584 | } |
4585 | |
4586 | |
4587 | //************* Triangulation |
4588 | |
4589 | #ifndef TRIANGULATE_H |
4590 | |
4591 | #define TRIANGULATE_H |
4592 | |
4593 | typedef uint32_t TU32; |
4594 | |
4595 | class TVec |
4596 | { |
4597 | public: |
4598 | TVec(double _x,double _y,double _z) { x = _x; y = _y; z = _z; }; |
4599 | TVec(void) { }; |
4600 | |
4601 | double x; |
4602 | double y; |
4603 | double z; |
4604 | }; |
4605 | |
4606 | typedef std::vector< TVec > TVecVector; |
4607 | typedef std::vector< TU32 > TU32Vector; |
4608 | |
4609 | class CTriangulator |
4610 | { |
4611 | public: |
4612 | /// Default constructor |
4613 | CTriangulator(); |
4614 | |
4615 | /// Default destructor |
4616 | virtual ~CTriangulator(); |
4617 | |
4618 | /// Triangulates the contour |
4619 | void triangulate(TU32Vector &indices); |
4620 | |
4621 | /// Returns the given point in the triangulator array |
4622 | inline TVec get(const TU32 id) { return mPoints[id]; } |
4623 | |
4624 | virtual void reset(void) |
4625 | { |
4626 | mInputPoints.clear(); |
4627 | mPoints.clear(); |
4628 | mIndices.clear(); |
4629 | } |
4630 | |
4631 | virtual void addPoint(double x,double y,double z) |
4632 | { |
4633 | TVec v(x,y,z); |
4634 | // update bounding box... |
4635 | if ( mInputPoints.empty() ) |
4636 | { |
4637 | mMin = v; |
4638 | mMax = v; |
4639 | } |
4640 | else |
4641 | { |
4642 | if ( x < mMin.x ) mMin.x = x; |
4643 | if ( y < mMin.y ) mMin.y = y; |
4644 | if ( z < mMin.z ) mMin.z = z; |
4645 | |
4646 | if ( x > mMax.x ) mMax.x = x; |
4647 | if ( y > mMax.y ) mMax.y = y; |
4648 | if ( z > mMax.z ) mMax.z = z; |
4649 | } |
4650 | mInputPoints.push_back(v); |
4651 | } |
4652 | |
4653 | // Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two most signficant axes |
4654 | // Here we find the two longest axes and use them to triangulate. Inverse transforming them would introduce more doubleing point error and isn't worth it. |
4655 | virtual uint32_t * triangulate(uint32_t &tcount,double epsilon) |
4656 | { |
4657 | uint32_t *ret = 0; |
4658 | tcount = 0; |
4659 | mEpsilon = epsilon; |
4660 | |
4661 | if ( !mInputPoints.empty() ) |
4662 | { |
4663 | mPoints.clear(); |
4664 | |
4665 | double dx = mMax.x - mMin.x; // locate the first, second and third longest edges and store them in i1, i2, i3 |
4666 | double dy = mMax.y - mMin.y; |
4667 | double dz = mMax.z - mMin.z; |
4668 | |
4669 | uint32_t i1,i2,i3; |
4670 | |
4671 | if ( dx > dy && dx > dz ) |
4672 | { |
4673 | i1 = 0; |
4674 | if ( dy > dz ) |
4675 | { |
4676 | i2 = 1; |
4677 | i3 = 2; |
4678 | } |
4679 | else |
4680 | { |
4681 | i2 = 2; |
4682 | i3 = 1; |
4683 | } |
4684 | } |
4685 | else if ( dy > dx && dy > dz ) |
4686 | { |
4687 | i1 = 1; |
4688 | if ( dx > dz ) |
4689 | { |
4690 | i2 = 0; |
4691 | i3 = 2; |
4692 | } |
4693 | else |
4694 | { |
4695 | i2 = 2; |
4696 | i3 = 0; |
4697 | } |
4698 | } |
4699 | else |
4700 | { |
4701 | i1 = 2; |
4702 | if ( dx > dy ) |
4703 | { |
4704 | i2 = 0; |
4705 | i3 = 1; |
4706 | } |
4707 | else |
4708 | { |
4709 | i2 = 1; |
4710 | i3 = 0; |
4711 | } |
4712 | } |
4713 | |
4714 | uint32_t pcount = (uint32_t)mInputPoints.size(); |
4715 | const double *points = &mInputPoints[0].x; |
4716 | for (uint32_t i=0; i<pcount; i++) |
4717 | { |
4718 | TVec v( points[i1], points[i2], points[i3] ); |
4719 | mPoints.push_back(v); |
4720 | points+=3; |
4721 | } |
4722 | |
4723 | mIndices.clear(); |
4724 | triangulate(mIndices); |
4725 | tcount = (uint32_t)mIndices.size()/3; |
4726 | if ( tcount ) |
4727 | { |
4728 | ret = &mIndices[0]; |
4729 | } |
4730 | } |
4731 | return ret; |
4732 | } |
4733 | |
4734 | virtual const double * getPoint(uint32_t index) |
4735 | { |
4736 | return &mInputPoints[index].x; |
4737 | } |
4738 | |
4739 | |
4740 | private: |
4741 | double mEpsilon; |
4742 | TVec mMin; |
4743 | TVec mMax; |
4744 | TVecVector mInputPoints; |
4745 | TVecVector mPoints; |
4746 | TU32Vector mIndices; |
4747 | |
4748 | /// Tests if a point is inside the given triangle |
4749 | bool _insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P); |
4750 | |
4751 | /// Returns the area of the contour |
4752 | double _area(); |
4753 | |
4754 | bool _snip(int32_t u, int32_t v, int32_t w, int32_t n, int32_t *V); |
4755 | |
4756 | /// Processes the triangulation |
4757 | void _process(TU32Vector &indices); |
4758 | |
4759 | }; |
4760 | |
4761 | /// Default constructor |
4762 | CTriangulator::CTriangulator(void) |
4763 | { |
4764 | } |
4765 | |
4766 | /// Default destructor |
4767 | CTriangulator::~CTriangulator() |
4768 | { |
4769 | } |
4770 | |
4771 | /// Triangulates the contour |
4772 | void CTriangulator::triangulate(TU32Vector &indices) |
4773 | { |
4774 | _process(indices); |
4775 | } |
4776 | |
4777 | /// Processes the triangulation |
4778 | void CTriangulator::_process(TU32Vector &indices) |
4779 | { |
4780 | const int32_t n = (const int32_t)mPoints.size(); |
4781 | if (n < 3) |
4782 | return; |
4783 | int32_t *V = (int32_t *)malloc(sizeof(int32_t)*n); |
4784 | |
4785 | bool flipped = false; |
4786 | |
4787 | if (0.0f < _area()) |
4788 | { |
4789 | for (int32_t v = 0; v < n; v++) |
4790 | V[v] = v; |
4791 | } |
4792 | else |
4793 | { |
4794 | flipped = true; |
4795 | for (int32_t v = 0; v < n; v++) |
4796 | V[v] = (n - 1) - v; |
4797 | } |
4798 | |
4799 | int32_t nv = n; |
4800 | int32_t count = 2 * nv; |
4801 | for (int32_t m = 0, v = nv - 1; nv > 2;) |
4802 | { |
4803 | if (0 >= (count--)) |
4804 | return; |
4805 | |
4806 | int32_t u = v; |
4807 | if (nv <= u) |
4808 | u = 0; |
4809 | v = u + 1; |
4810 | if (nv <= v) |
4811 | v = 0; |
4812 | int32_t w = v + 1; |
4813 | if (nv <= w) |
4814 | w = 0; |
4815 | |
4816 | if (_snip(u, v, w, nv, V)) |
4817 | { |
4818 | int32_t a, b, c, s, t; |
4819 | a = V[u]; |
4820 | b = V[v]; |
4821 | c = V[w]; |
4822 | if ( flipped ) |
4823 | { |
4824 | indices.push_back(a); |
4825 | indices.push_back(b); |
4826 | indices.push_back(c); |
4827 | } |
4828 | else |
4829 | { |
4830 | indices.push_back(c); |
4831 | indices.push_back(b); |
4832 | indices.push_back(a); |
4833 | } |
4834 | m++; |
4835 | for (s = v, t = v + 1; t < nv; s++, t++) |
4836 | V[s] = V[t]; |
4837 | nv--; |
4838 | count = 2 * nv; |
4839 | } |
4840 | } |
4841 | |
4842 | free(V); |
4843 | } |
4844 | |
4845 | /// Returns the area of the contour |
4846 | double CTriangulator::_area() |
4847 | { |
4848 | int32_t n = (uint32_t)mPoints.size(); |
4849 | double A = 0.0f; |
4850 | for (int32_t p = n - 1, q = 0; q < n; p = q++) |
4851 | { |
4852 | const TVec &pval = mPoints[p]; |
4853 | const TVec &qval = mPoints[q]; |
4854 | A += pval.x * qval.y - qval.x * pval.y; |
4855 | } |
4856 | A*=0.5f; |
4857 | return A; |
4858 | } |
4859 | |
4860 | bool CTriangulator::_snip(int32_t u, int32_t v, int32_t w, int32_t n, int32_t *V) |
4861 | { |
4862 | int32_t p; |
4863 | |
4864 | const TVec &A = mPoints[ V[u] ]; |
4865 | const TVec &B = mPoints[ V[v] ]; |
4866 | const TVec &C = mPoints[ V[w] ]; |
4867 | |
4868 | if (mEpsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))) ) |
4869 | return false; |
4870 | |
4871 | for (p = 0; p < n; p++) |
4872 | { |
4873 | if ((p == u) || (p == v) || (p == w)) |
4874 | continue; |
4875 | const TVec &P = mPoints[ V[p] ]; |
4876 | if (_insideTriangle(A, B, C, P)) |
4877 | return false; |
4878 | } |
4879 | return true; |
4880 | } |
4881 | |
4882 | /// Tests if a point is inside the given triangle |
4883 | bool CTriangulator::_insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P) |
4884 | { |
4885 | double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; |
4886 | double cCROSSap, bCROSScp, aCROSSbp; |
4887 | |
4888 | ax = C.x - B.x; ay = C.y - B.y; |
4889 | bx = A.x - C.x; by = A.y - C.y; |
4890 | cx = B.x - A.x; cy = B.y - A.y; |
4891 | apx = P.x - A.x; apy = P.y - A.y; |
4892 | bpx = P.x - B.x; bpy = P.y - B.y; |
4893 | cpx = P.x - C.x; cpy = P.y - C.y; |
4894 | |
4895 | aCROSSbp = ax * bpy - ay * bpx; |
4896 | cCROSSap = cx * apy - cy * apx; |
4897 | bCROSScp = bx * cpy - by * cpx; |
4898 | |
4899 | return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); |
4900 | } |
4901 | |
4902 | class Triangulate : public fm_Triangulate |
4903 | { |
4904 | public: |
4905 | Triangulate(void) |
4906 | { |
4907 | mPointsFloat = 0; |
4908 | mPointsDouble = 0; |
4909 | } |
4910 | |
4911 | virtual ~Triangulate(void) |
4912 | { |
4913 | reset(); |
4914 | } |
4915 | void reset(void) |
4916 | { |
4917 | free(mPointsFloat); |
4918 | free(mPointsDouble); |
4919 | mPointsFloat = 0; |
4920 | mPointsDouble = 0; |
4921 | } |
4922 | |
4923 | virtual const double * triangulate3d(uint32_t pcount, |
4924 | const double *_points, |
4925 | uint32_t vstride, |
4926 | uint32_t &tcount, |
4927 | bool consolidate, |
4928 | double epsilon) |
4929 | { |
4930 | reset(); |
4931 | |
4932 | double *points = (double *)malloc(sizeof(double)*pcount*3); |
4933 | if ( consolidate ) |
4934 | { |
4935 | pcount = fm_consolidatePolygon(pcount,_points,vstride,points,1-epsilon); |
4936 | } |
4937 | else |
4938 | { |
4939 | double *dest = points; |
4940 | for (uint32_t i=0; i<pcount; i++) |
4941 | { |
4942 | const double *src = fm_getPoint(_points,vstride,i); |
4943 | dest[0] = src[0]; |
4944 | dest[1] = src[1]; |
4945 | dest[2] = src[2]; |
4946 | dest+=3; |
4947 | } |
4948 | vstride = sizeof(double)*3; |
4949 | } |
4950 | |
4951 | if ( pcount >= 3 ) |
4952 | { |
4953 | CTriangulator ct; |
4954 | for (uint32_t i=0; i<pcount; i++) |
4955 | { |
4956 | const double *src = fm_getPoint(points,vstride,i); |
4957 | ct.addPoint( src[0], src[1], src[2] ); |
4958 | } |
4959 | uint32_t _tcount; |
4960 | uint32_t *indices = ct.triangulate(_tcount,epsilon); |
4961 | if ( indices ) |
4962 | { |
4963 | tcount = _tcount; |
4964 | mPointsDouble = (double *)malloc(sizeof(double)*tcount*3*3); |
4965 | double *dest = mPointsDouble; |
4966 | for (uint32_t i=0; i<tcount; i++) |
4967 | { |
4968 | uint32_t i1 = indices[i*3+0]; |
4969 | uint32_t i2 = indices[i*3+1]; |
4970 | uint32_t i3 = indices[i*3+2]; |
4971 | const double *p1 = ct.getPoint(i1); |
4972 | const double *p2 = ct.getPoint(i2); |
4973 | const double *p3 = ct.getPoint(i3); |
4974 | |
4975 | dest[0] = p1[0]; |
4976 | dest[1] = p1[1]; |
4977 | dest[2] = p1[2]; |
4978 | |
4979 | dest[3] = p2[0]; |
4980 | dest[4] = p2[1]; |
4981 | dest[5] = p2[2]; |
4982 | |
4983 | dest[6] = p3[0]; |
4984 | dest[7] = p3[1]; |
4985 | dest[8] = p3[2]; |
4986 | dest+=9; |
4987 | } |
4988 | } |
4989 | } |
4990 | free(points); |
4991 | |
4992 | return mPointsDouble; |
4993 | } |
4994 | |
4995 | virtual const float * triangulate3d(uint32_t pcount, |
4996 | const float *points, |
4997 | uint32_t vstride, |
4998 | uint32_t &tcount, |
4999 | bool consolidate, |
5000 | float epsilon) |
5001 | { |
5002 | reset(); |
5003 | |
5004 | double *temp = (double *)malloc(sizeof(double)*pcount*3); |
5005 | double *dest = temp; |
5006 | for (uint32_t i=0; i<pcount; i++) |
5007 | { |
5008 | const float *p = fm_getPoint(points,vstride,i); |
5009 | dest[0] = p[0]; |
5010 | dest[1] = p[1]; |
5011 | dest[2] = p[2]; |
5012 | dest+=3; |
5013 | } |
5014 | const double *results = triangulate3d(pcount,temp,sizeof(double)*3,tcount,consolidate,epsilon); |
5015 | if ( results ) |
5016 | { |
5017 | uint32_t fcount = tcount*3*3; |
5018 | mPointsFloat = (float *)malloc(sizeof(float)*tcount*3*3); |
5019 | for (uint32_t i=0; i<fcount; i++) |
5020 | { |
5021 | mPointsFloat[i] = (float) results[i]; |
5022 | } |
5023 | free(mPointsDouble); |
5024 | mPointsDouble = 0; |
5025 | } |
5026 | free(temp); |
5027 | |
5028 | return mPointsFloat; |
5029 | } |
5030 | |
5031 | private: |
5032 | float *mPointsFloat; |
5033 | double *mPointsDouble; |
5034 | }; |
5035 | |
5036 | fm_Triangulate * fm_createTriangulate(void) |
5037 | { |
5038 | Triangulate *t = new Triangulate; |
5039 | return static_cast< fm_Triangulate *>(t); |
5040 | } |
5041 | |
5042 | void fm_releaseTriangulate(fm_Triangulate *t) |
5043 | { |
5044 | Triangulate *tt = static_cast< Triangulate *>(t); |
5045 | delete tt; |
5046 | } |
5047 | |
5048 | #endif |
5049 | |
5050 | bool validDistance(const REAL *p1,const REAL *p2,REAL epsilon) |
5051 | { |
5052 | bool ret = true; |
5053 | |
5054 | REAL dx = p1[0] - p2[0]; |
5055 | REAL dy = p1[1] - p2[1]; |
5056 | REAL dz = p1[2] - p2[2]; |
5057 | REAL dist = dx*dx+dy*dy+dz*dz; |
5058 | if ( dist < (epsilon*epsilon) ) |
5059 | { |
5060 | ret = false; |
5061 | } |
5062 | return ret; |
5063 | } |
5064 | |
5065 | bool fm_isValidTriangle(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) |
5066 | { |
5067 | bool ret = false; |
5068 | |
5069 | if ( validDistance(p1,p2,epsilon) && |
5070 | validDistance(p1,p3,epsilon) && |
5071 | validDistance(p2,p3,epsilon) ) |
5072 | { |
5073 | |
5074 | REAL area = fm_computeArea(p1,p2,p3); |
5075 | if ( area > epsilon ) |
5076 | { |
5077 | REAL _vertices[3*3],vertices[64*3]; |
5078 | |
5079 | _vertices[0] = p1[0]; |
5080 | _vertices[1] = p1[1]; |
5081 | _vertices[2] = p1[2]; |
5082 | |
5083 | _vertices[3] = p2[0]; |
5084 | _vertices[4] = p2[1]; |
5085 | _vertices[5] = p2[2]; |
5086 | |
5087 | _vertices[6] = p3[0]; |
5088 | _vertices[7] = p3[1]; |
5089 | _vertices[8] = p3[2]; |
5090 | |
5091 | uint32_t pcount = fm_consolidatePolygon(3,_vertices,sizeof(REAL)*3,vertices,1-epsilon); |
5092 | if ( pcount == 3 ) |
5093 | { |
5094 | ret = true; |
5095 | } |
5096 | } |
5097 | } |
5098 | return ret; |
5099 | } |
5100 | |
5101 | |
5102 | void fm_multiplyQuat(const REAL *left,const REAL *right,REAL *quat) |
5103 | { |
5104 | REAL a,b,c,d; |
5105 | |
5106 | a = left[3]*right[3] - left[0]*right[0] - left[1]*right[1] - left[2]*right[2]; |
5107 | b = left[3]*right[0] + right[3]*left[0] + left[1]*right[2] - right[1]*left[2]; |
5108 | c = left[3]*right[1] + right[3]*left[1] + left[2]*right[0] - right[2]*left[0]; |
5109 | d = left[3]*right[2] + right[3]*left[2] + left[0]*right[1] - right[0]*left[1]; |
5110 | |
5111 | quat[3] = a; |
5112 | quat[0] = b; |
5113 | quat[1] = c; |
5114 | quat[2] = d; |
5115 | } |
5116 | |
5117 | bool fm_computeCentroid(uint32_t vcount, // number of input data points |
5118 | const REAL *points, // starting address of points array. |
5119 | REAL *center) |
5120 | |
5121 | { |
5122 | bool ret = false; |
5123 | if ( vcount ) |
5124 | { |
5125 | center[0] = 0; |
5126 | center[1] = 0; |
5127 | center[2] = 0; |
5128 | const REAL *p = points; |
5129 | for (uint32_t i=0; i<vcount; i++) |
5130 | { |
5131 | center[0]+=p[0]; |
5132 | center[1]+=p[1]; |
5133 | center[2]+=p[2]; |
5134 | p += 3; |
5135 | } |
5136 | REAL recip = 1.0f / (REAL)vcount; |
5137 | center[0]*=recip; |
5138 | center[1]*=recip; |
5139 | center[2]*=recip; |
5140 | ret = true; |
5141 | } |
5142 | return ret; |
5143 | } |
5144 | |
5145 | bool fm_computeCentroid(uint32_t vcount, // number of input data points |
5146 | const REAL *points, // starting address of points array. |
5147 | uint32_t triCount, |
5148 | const uint32_t *indices, |
5149 | REAL *center) |
5150 | |
5151 | { |
5152 | bool ret = false; |
5153 | if (vcount) |
5154 | { |
5155 | center[0] = 0; |
5156 | center[1] = 0; |
5157 | center[2] = 0; |
5158 | |
5159 | REAL numerator[3] = { 0, 0, 0 }; |
5160 | REAL denomintaor = 0; |
5161 | |
5162 | for (uint32_t i = 0; i < triCount; i++) |
5163 | { |
5164 | uint32_t i1 = indices[i * 3 + 0]; |
5165 | uint32_t i2 = indices[i * 3 + 1]; |
5166 | uint32_t i3 = indices[i * 3 + 2]; |
5167 | |
5168 | const REAL *p1 = &points[i1 * 3]; |
5169 | const REAL *p2 = &points[i2 * 3]; |
5170 | const REAL *p3 = &points[i3 * 3]; |
5171 | |
5172 | // Compute the sum of the three positions |
5173 | REAL sum[3]; |
5174 | sum[0] = p1[0] + p2[0] + p3[0]; |
5175 | sum[1] = p1[1] + p2[1] + p3[1]; |
5176 | sum[2] = p1[2] + p2[2] + p3[2]; |
5177 | |
5178 | // Compute the average of the three positions |
5179 | sum[0] = sum[0] / 3; |
5180 | sum[1] = sum[1] / 3; |
5181 | sum[2] = sum[2] / 3; |
5182 | |
5183 | // Compute the area of this triangle |
5184 | REAL area = fm_computeArea(p1, p2, p3); |
5185 | |
5186 | numerator[0]+= (sum[0] * area); |
5187 | numerator[1]+= (sum[1] * area); |
5188 | numerator[2]+= (sum[2] * area); |
5189 | |
5190 | denomintaor += area; |
5191 | |
5192 | } |
5193 | REAL recip = 1 / denomintaor; |
5194 | center[0] = numerator[0] * recip; |
5195 | center[1] = numerator[1] * recip; |
5196 | center[2] = numerator[2] * recip; |
5197 | ret = true; |
5198 | } |
5199 | return ret; |
5200 | } |
5201 | |
5202 | |
5203 | #ifndef TEMPLATE_VEC3 |
5204 | #define TEMPLATE_VEC3 |
5205 | template <class Type> class Vec3 |
5206 | { |
5207 | public: |
5208 | Vec3(void) |
5209 | { |
5210 | |
5211 | } |
5212 | Vec3(Type _x,Type _y,Type _z) |
5213 | { |
5214 | x = _x; |
5215 | y = _y; |
5216 | z = _z; |
5217 | } |
5218 | Type x; |
5219 | Type y; |
5220 | Type z; |
5221 | }; |
5222 | #endif |
5223 | |
5224 | void fm_transformAABB(const REAL bmin[3],const REAL bmax[3],const REAL matrix[16],REAL tbmin[3],REAL tbmax[3]) |
5225 | { |
5226 | Vec3<REAL> box[8]; |
5227 | box[0] = Vec3< REAL >( bmin[0], bmin[1], bmin[2] ); |
5228 | box[1] = Vec3< REAL >( bmax[0], bmin[1], bmin[2] ); |
5229 | box[2] = Vec3< REAL >( bmax[0], bmax[1], bmin[2] ); |
5230 | box[3] = Vec3< REAL >( bmin[0], bmax[1], bmin[2] ); |
5231 | box[4] = Vec3< REAL >( bmin[0], bmin[1], bmax[2] ); |
5232 | box[5] = Vec3< REAL >( bmax[0], bmin[1], bmax[2] ); |
5233 | box[6] = Vec3< REAL >( bmax[0], bmax[1], bmax[2] ); |
5234 | box[7] = Vec3< REAL >( bmin[0], bmax[1], bmax[2] ); |
5235 | // transform all 8 corners of the box and then recompute a new AABB |
5236 | for (unsigned int i=0; i<8; i++) |
5237 | { |
5238 | Vec3< REAL > &p = box[i]; |
5239 | fm_transform(matrix,&p.x,&p.x); |
5240 | if ( i == 0 ) |
5241 | { |
5242 | tbmin[0] = tbmax[0] = p.x; |
5243 | tbmin[1] = tbmax[1] = p.y; |
5244 | tbmin[2] = tbmax[2] = p.z; |
5245 | } |
5246 | else |
5247 | { |
5248 | if ( p.x < tbmin[0] ) tbmin[0] = p.x; |
5249 | if ( p.y < tbmin[1] ) tbmin[1] = p.y; |
5250 | if ( p.z < tbmin[2] ) tbmin[2] = p.z; |
5251 | if ( p.x > tbmax[0] ) tbmax[0] = p.x; |
5252 | if ( p.y > tbmax[1] ) tbmax[1] = p.y; |
5253 | if ( p.z > tbmax[2] ) tbmax[2] = p.z; |
5254 | } |
5255 | } |
5256 | } |
5257 | |
5258 | REAL fm_normalizeQuat(REAL n[4]) // normalize this quat |
5259 | { |
5260 | REAL dx = n[0]*n[0]; |
5261 | REAL dy = n[1]*n[1]; |
5262 | REAL dz = n[2]*n[2]; |
5263 | REAL dw = n[3]*n[3]; |
5264 | |
5265 | REAL dist = dx*dx+dy*dy+dz*dz+dw*dw; |
5266 | |
5267 | dist = (REAL)sqrt(dist); |
5268 | |
5269 | REAL recip = 1.0f / dist; |
5270 | |
5271 | n[0]*=recip; |
5272 | n[1]*=recip; |
5273 | n[2]*=recip; |
5274 | n[3]*=recip; |
5275 | |
5276 | return dist; |
5277 | } |
5278 | |
5279 | |
5280 | }; // end of namespace |
5281 | |