2
Copyright (C) 2006, 2008 Sony Computer Entertainment Inc.
5
This software is provided 'as-is', without any express or implied warranty.
6
In no event will the authors be held liable for any damages arising from the use of this software.
7
Permission is granted to anyone to use this software for any purpose,
8
including commercial applications, and to alter it and redistribute it freely,
9
subject to the following restrictions:
11
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13
3. This notice may not be removed or altered from any source distribution.
18
//#include "PfxContactBoxBox.h"
21
#include "../PlatformDefinitions.h"
22
#include "boxBoxDistance.h"
24
static inline float sqr( float a )
31
A_AXIS, B_AXIS, CROSS_AXIS
34
//-------------------------------------------------------------------------------------------------
35
// voronoiTol: bevels Voronoi planes slightly which helps when features are parallel.
36
//-------------------------------------------------------------------------------------------------
38
static const float voronoiTol = -1.0e-5f;
40
//-------------------------------------------------------------------------------------------------
41
// separating axis tests: gaps along each axis are computed, and the axis with the maximum
42
// gap is stored. cross product axes are normalized.
43
//-------------------------------------------------------------------------------------------------
45
#define AaxisTest( dim, letter, first ) \
49
maxGap = gap = gapsA.get##letter(); \
50
if ( gap > distanceThreshold ) return gap; \
53
axisA = identity.getCol##dim(); \
57
gap = gapsA.get##letter(); \
58
if ( gap > distanceThreshold ) return gap; \
59
else if ( gap > maxGap ) \
64
axisA = identity.getCol##dim(); \
70
#define BaxisTest( dim, letter ) \
72
gap = gapsB.get##letter(); \
73
if ( gap > distanceThreshold ) return gap; \
74
else if ( gap > maxGap ) \
79
axisB = identity.getCol##dim(); \
83
#define CrossAxisTest( dima, dimb, letterb ) \
85
const float lsqr_tolerance = 1.0e-30f; \
88
lsqr = lsqrs.getCol##dima().get##letterb(); \
90
if ( lsqr > lsqr_tolerance ) \
92
float l_recip = 1.0f / sqrtf( lsqr ); \
93
gap = float(gapsAxB.getCol##dima().get##letterb()) * l_recip; \
95
if ( gap > distanceThreshold ) \
100
if ( gap > maxGap ) \
103
axisType = CROSS_AXIS; \
106
axisA = cross(identity.getCol##dima(),matrixAB.getCol##dimb()) * l_recip; \
111
//-------------------------------------------------------------------------------------------------
112
// tests whether a vertex of box B and a face of box A are the closest features
113
//-------------------------------------------------------------------------------------------------
121
const vmVector3 & hA,
122
PE_REF(vmVector3) faceOffsetAB,
123
PE_REF(vmVector3) faceOffsetBA,
124
const vmMatrix3 & matrixAB,
125
const vmMatrix3 & matrixBA,
126
PE_REF(vmVector3) signsB,
127
PE_REF(vmVector3) scalesB )
129
// compute a corner of box B in A's coordinate system
132
vmVector3( faceOffsetAB + matrixAB.getCol0() * scalesB.getX() + matrixAB.getCol1() * scalesB.getY() );
134
// compute the parameters of the point on A, closest to this corner
141
else if ( t0 < -hA[0] )
145
else if ( t1 < -hA[1] )
148
// do the Voronoi test: already know the point on B is in the Voronoi region of the
149
// point on A, check the reverse.
151
vmVector3 facePointB =
152
vmVector3( mulPerElem( faceOffsetBA + matrixBA.getCol0() * t0 + matrixBA.getCol1() * t1 - scalesB, signsB ) );
154
inVoronoi = ( ( facePointB[0] >= voronoiTol * facePointB[2] ) &&
155
( facePointB[1] >= voronoiTol * facePointB[0] ) &&
156
( facePointB[2] >= voronoiTol * facePointB[1] ) );
158
return (sqr( corner[0] - t0 ) + sqr( corner[1] - t1 ) + sqr( corner[2] ));
161
#define VertexBFaceA_SetNewMin() \
163
minDistSqr = distSqr; \
164
localPointA.setX(t0); \
165
localPointA.setY(t1); \
166
localPointB.setX( scalesB.getX() ); \
167
localPointB.setY( scalesB.getY() ); \
176
vmPoint3 & localPointA,
177
vmPoint3 & localPointB,
178
FeatureType & featureA,
179
FeatureType & featureB,
180
const vmVector3 & hA,
181
PE_REF(vmVector3) faceOffsetAB,
182
PE_REF(vmVector3) faceOffsetBA,
183
const vmMatrix3 & matrixAB,
184
const vmMatrix3 & matrixBA,
185
PE_REF(vmVector3) signsB,
186
PE_REF(vmVector3) scalesB,
193
distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA,
194
matrixAB, matrixBA, signsB, scalesB );
197
VertexBFaceA_SetNewMin();
199
if ( distSqr < minDistSqr ) {
200
VertexBFaceA_SetNewMin();
207
signsB.setX( -signsB.getX() );
208
scalesB.setX( -scalesB.getX() );
210
distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA,
211
matrixAB, matrixBA, signsB, scalesB );
213
if ( distSqr < minDistSqr ) {
214
VertexBFaceA_SetNewMin();
220
signsB.setY( -signsB.getY() );
221
scalesB.setY( -scalesB.getY() );
223
distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA,
224
matrixAB, matrixBA, signsB, scalesB );
226
if ( distSqr < minDistSqr ) {
227
VertexBFaceA_SetNewMin();
233
signsB.setX( -signsB.getX() );
234
scalesB.setX( -scalesB.getX() );
236
distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA,
237
matrixAB, matrixBA, signsB, scalesB );
239
if ( distSqr < minDistSqr ) {
240
VertexBFaceA_SetNewMin();
244
//-------------------------------------------------------------------------------------------------
245
// VertexAFaceBTest: tests whether a vertex of box A and a face of box B are the closest features
246
//-------------------------------------------------------------------------------------------------
254
const vmVector3 & hB,
255
PE_REF(vmVector3) faceOffsetAB,
256
PE_REF(vmVector3) faceOffsetBA,
257
const vmMatrix3 & matrixAB,
258
const vmMatrix3 & matrixBA,
259
PE_REF(vmVector3) signsA,
260
PE_REF(vmVector3) scalesA )
263
vmVector3( faceOffsetBA + matrixBA.getCol0() * scalesA.getX() + matrixBA.getCol1() * scalesA.getY() );
270
else if ( t0 < -hB[0] )
274
else if ( t1 < -hB[1] )
277
vmVector3 facePointA =
278
vmVector3( mulPerElem( faceOffsetAB + matrixAB.getCol0() * t0 + matrixAB.getCol1() * t1 - scalesA, signsA ) );
280
inVoronoi = ( ( facePointA[0] >= voronoiTol * facePointA[2] ) &&
281
( facePointA[1] >= voronoiTol * facePointA[0] ) &&
282
( facePointA[2] >= voronoiTol * facePointA[1] ) );
284
return (sqr( corner[0] - t0 ) + sqr( corner[1] - t1 ) + sqr( corner[2] ));
287
#define VertexAFaceB_SetNewMin() \
289
minDistSqr = distSqr; \
290
localPointB.setX(t0); \
291
localPointB.setY(t1); \
292
localPointA.setX( scalesA.getX() ); \
293
localPointA.setY( scalesA.getY() ); \
302
vmPoint3 & localPointA,
303
vmPoint3 & localPointB,
304
FeatureType & featureA,
305
FeatureType & featureB,
306
const vmVector3 & hB,
307
PE_REF(vmVector3) faceOffsetAB,
308
PE_REF(vmVector3) faceOffsetBA,
309
const vmMatrix3 & matrixAB,
310
const vmMatrix3 & matrixBA,
311
PE_REF(vmVector3) signsA,
312
PE_REF(vmVector3) scalesA,
318
distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA,
319
matrixAB, matrixBA, signsA, scalesA );
322
VertexAFaceB_SetNewMin();
324
if ( distSqr < minDistSqr ) {
325
VertexAFaceB_SetNewMin();
332
signsA.setX( -signsA.getX() );
333
scalesA.setX( -scalesA.getX() );
335
distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA,
336
matrixAB, matrixBA, signsA, scalesA );
338
if ( distSqr < minDistSqr ) {
339
VertexAFaceB_SetNewMin();
345
signsA.setY( -signsA.getY() );
346
scalesA.setY( -scalesA.getY() );
348
distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA,
349
matrixAB, matrixBA, signsA, scalesA );
351
if ( distSqr < minDistSqr ) {
352
VertexAFaceB_SetNewMin();
358
signsA.setX( -signsA.getX() );
359
scalesA.setX( -scalesA.getX() );
361
distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA,
362
matrixAB, matrixBA, signsA, scalesA );
364
if ( distSqr < minDistSqr ) {
365
VertexAFaceB_SetNewMin();
369
//-------------------------------------------------------------------------------------------------
370
// CustomEdgeEdgeTest:
372
// tests whether a pair of edges are the closest features
374
// note on the shorthand:
375
// 'a' & 'b' refer to the edges.
376
// 'c' is the dimension of the axis that points from the face center to the edge Center
377
// 'd' is the dimension of the edge Direction
378
// the dimension of the face normal is 2
379
//-------------------------------------------------------------------------------------------------
381
#define CustomEdgeEdgeTest( ac, ac_letter, ad, ad_letter, bc, bc_letter, bd, bd_letter ) \
383
vmVector3 edgeOffsetAB; \
384
vmVector3 edgeOffsetBA; \
386
edgeOffsetAB = faceOffsetAB + matrixAB.getCol##bc() * scalesB.get##bc_letter(); \
387
edgeOffsetAB.set##ac_letter( edgeOffsetAB.get##ac_letter() - scalesA.get##ac_letter() ); \
389
edgeOffsetBA = faceOffsetBA + matrixBA.getCol##ac() * scalesA.get##ac_letter(); \
390
edgeOffsetBA.set##bc_letter( edgeOffsetBA.get##bc_letter() - scalesB.get##bc_letter() ); \
392
float dirDot = matrixAB.getCol##bd().get##ad_letter(); \
393
float denom = 1.0f - dirDot*dirDot; \
394
float edgeOffsetAB_ad = edgeOffsetAB.get##ad_letter(); \
395
float edgeOffsetBA_bd = edgeOffsetBA.get##bd_letter(); \
397
if ( denom == 0.0f ) \
403
tA = ( edgeOffsetAB_ad + edgeOffsetBA_bd * dirDot ) / denom; \
406
if ( tA < -hA[ad] ) tA = -hA[ad]; \
407
else if ( tA > hA[ad] ) tA = hA[ad]; \
409
tB = tA * dirDot + edgeOffsetBA_bd; \
411
if ( tB < -hB[bd] ) \
414
tA = tB * dirDot + edgeOffsetAB_ad; \
416
if ( tA < -hA[ad] ) tA = -hA[ad]; \
417
else if ( tA > hA[ad] ) tA = hA[ad]; \
419
else if ( tB > hB[bd] ) \
422
tA = tB * dirDot + edgeOffsetAB_ad; \
424
if ( tA < -hA[ad] ) tA = -hA[ad]; \
425
else if ( tA > hA[ad] ) tA = hA[ad]; \
428
vmVector3 edgeOffAB = vmVector3( mulPerElem( edgeOffsetAB + matrixAB.getCol##bd() * tB, signsA ) );\
429
vmVector3 edgeOffBA = vmVector3( mulPerElem( edgeOffsetBA + matrixBA.getCol##ad() * tA, signsB ) );\
431
inVoronoi = ( edgeOffAB[ac] >= voronoiTol * edgeOffAB[2] ) && \
432
( edgeOffAB[2] >= voronoiTol * edgeOffAB[ac] ) && \
433
( edgeOffBA[bc] >= voronoiTol * edgeOffBA[2] ) && \
434
( edgeOffBA[2] >= voronoiTol * edgeOffBA[bc] ); \
436
edgeOffAB[ad] -= tA; \
437
edgeOffBA[bd] -= tB; \
439
return dot(edgeOffAB,edgeOffAB); \
443
CustomEdgeEdgeTest_0101(
447
const vmVector3 & hA,
448
const vmVector3 & hB,
449
PE_REF(vmVector3) faceOffsetAB,
450
PE_REF(vmVector3) faceOffsetBA,
451
const vmMatrix3 & matrixAB,
452
const vmMatrix3 & matrixBA,
453
PE_REF(vmVector3) signsA,
454
PE_REF(vmVector3) signsB,
455
PE_REF(vmVector3) scalesA,
456
PE_REF(vmVector3) scalesB )
458
CustomEdgeEdgeTest( 0, X, 1, Y, 0, X, 1, Y );
462
CustomEdgeEdgeTest_0110(
466
const vmVector3 & hA,
467
const vmVector3 & hB,
468
PE_REF(vmVector3) faceOffsetAB,
469
PE_REF(vmVector3) faceOffsetBA,
470
const vmMatrix3 & matrixAB,
471
const vmMatrix3 & matrixBA,
472
PE_REF(vmVector3) signsA,
473
PE_REF(vmVector3) signsB,
474
PE_REF(vmVector3) scalesA,
475
PE_REF(vmVector3) scalesB )
477
CustomEdgeEdgeTest( 0, X, 1, Y, 1, Y, 0, X );
481
CustomEdgeEdgeTest_1001(
485
const vmVector3 & hA,
486
const vmVector3 & hB,
487
PE_REF(vmVector3) faceOffsetAB,
488
PE_REF(vmVector3) faceOffsetBA,
489
const vmMatrix3 & matrixAB,
490
const vmMatrix3 & matrixBA,
491
PE_REF(vmVector3) signsA,
492
PE_REF(vmVector3) signsB,
493
PE_REF(vmVector3) scalesA,
494
PE_REF(vmVector3) scalesB )
496
CustomEdgeEdgeTest( 1, Y, 0, X, 0, X, 1, Y );
500
CustomEdgeEdgeTest_1010(
504
const vmVector3 & hA,
505
const vmVector3 & hB,
506
PE_REF(vmVector3) faceOffsetAB,
507
PE_REF(vmVector3) faceOffsetBA,
508
const vmMatrix3 & matrixAB,
509
const vmMatrix3 & matrixBA,
510
PE_REF(vmVector3) signsA,
511
PE_REF(vmVector3) signsB,
512
PE_REF(vmVector3) scalesA,
513
PE_REF(vmVector3) scalesB )
515
CustomEdgeEdgeTest( 1, Y, 0, X, 1, Y, 0, X );
518
#define EdgeEdge_SetNewMin( ac_letter, ad_letter, bc_letter, bd_letter ) \
520
minDistSqr = distSqr; \
521
localPointA.set##ac_letter(scalesA.get##ac_letter()); \
522
localPointA.set##ad_letter(tA); \
523
localPointB.set##bc_letter(scalesB.get##bc_letter()); \
524
localPointB.set##bd_letter(tB); \
525
otherFaceDimA = testOtherFaceDimA; \
526
otherFaceDimB = testOtherFaceDimB; \
535
vmPoint3 & localPointA,
536
vmPoint3 & localPointB,
539
FeatureType & featureA,
540
FeatureType & featureB,
541
const vmVector3 & hA,
542
const vmVector3 & hB,
543
PE_REF(vmVector3) faceOffsetAB,
544
PE_REF(vmVector3) faceOffsetBA,
545
const vmMatrix3 & matrixAB,
546
const vmMatrix3 & matrixBA,
547
PE_REF(vmVector3) signsA,
548
PE_REF(vmVector3) signsB,
549
PE_REF(vmVector3) scalesA,
550
PE_REF(vmVector3) scalesB,
557
int testOtherFaceDimA, testOtherFaceDimB;
559
testOtherFaceDimA = 0;
560
testOtherFaceDimB = 0;
562
distSqr = CustomEdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
563
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
566
EdgeEdge_SetNewMin( X, Y, X, Y );
568
if ( distSqr < minDistSqr ) {
569
EdgeEdge_SetNewMin( X, Y, X, Y );
576
signsA.setX( -signsA.getX() );
577
scalesA.setX( -scalesA.getX() );
579
distSqr = CustomEdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
580
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
582
if ( distSqr < minDistSqr ) {
583
EdgeEdge_SetNewMin( X, Y, X, Y );
589
signsB.setX( -signsB.getX() );
590
scalesB.setX( -scalesB.getX() );
592
distSqr = CustomEdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
593
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
595
if ( distSqr < minDistSqr ) {
596
EdgeEdge_SetNewMin( X, Y, X, Y );
602
signsA.setX( -signsA.getX() );
603
scalesA.setX( -scalesA.getX() );
605
distSqr = CustomEdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
606
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
608
if ( distSqr < minDistSqr ) {
609
EdgeEdge_SetNewMin( X, Y, X, Y );
615
testOtherFaceDimA = 1;
616
testOtherFaceDimB = 0;
617
signsB.setX( -signsB.getX() );
618
scalesB.setX( -scalesB.getX() );
620
distSqr = CustomEdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
621
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
623
if ( distSqr < minDistSqr ) {
624
EdgeEdge_SetNewMin( Y, X, X, Y );
630
signsA.setY( -signsA.getY() );
631
scalesA.setY( -scalesA.getY() );
633
distSqr = CustomEdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
634
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
636
if ( distSqr < minDistSqr ) {
637
EdgeEdge_SetNewMin( Y, X, X, Y );
643
signsB.setX( -signsB.getX() );
644
scalesB.setX( -scalesB.getX() );
646
distSqr = CustomEdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
647
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
649
if ( distSqr < minDistSqr ) {
650
EdgeEdge_SetNewMin( Y, X, X, Y );
656
signsA.setY( -signsA.getY() );
657
scalesA.setY( -scalesA.getY() );
659
distSqr = CustomEdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
660
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
662
if ( distSqr < minDistSqr ) {
663
EdgeEdge_SetNewMin( Y, X, X, Y );
669
testOtherFaceDimA = 0;
670
testOtherFaceDimB = 1;
671
signsB.setX( -signsB.getX() );
672
scalesB.setX( -scalesB.getX() );
674
distSqr = CustomEdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
675
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
677
if ( distSqr < minDistSqr ) {
678
EdgeEdge_SetNewMin( X, Y, Y, X );
684
signsA.setX( -signsA.getX() );
685
scalesA.setX( -scalesA.getX() );
687
distSqr = CustomEdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
688
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
690
if ( distSqr < minDistSqr ) {
691
EdgeEdge_SetNewMin( X, Y, Y, X );
697
signsB.setY( -signsB.getY() );
698
scalesB.setY( -scalesB.getY() );
700
distSqr = CustomEdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
701
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
703
if ( distSqr < minDistSqr ) {
704
EdgeEdge_SetNewMin( X, Y, Y, X );
710
signsA.setX( -signsA.getX() );
711
scalesA.setX( -scalesA.getX() );
713
distSqr = CustomEdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
714
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
716
if ( distSqr < minDistSqr ) {
717
EdgeEdge_SetNewMin( X, Y, Y, X );
723
testOtherFaceDimA = 1;
724
testOtherFaceDimB = 1;
725
signsB.setY( -signsB.getY() );
726
scalesB.setY( -scalesB.getY() );
728
distSqr = CustomEdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
729
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
731
if ( distSqr < minDistSqr ) {
732
EdgeEdge_SetNewMin( Y, X, Y, X );
738
signsA.setY( -signsA.getY() );
739
scalesA.setY( -scalesA.getY() );
741
distSqr = CustomEdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
742
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
744
if ( distSqr < minDistSqr ) {
745
EdgeEdge_SetNewMin( Y, X, Y, X );
751
signsB.setY( -signsB.getY() );
752
scalesB.setY( -scalesB.getY() );
754
distSqr = CustomEdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
755
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
757
if ( distSqr < minDistSqr ) {
758
EdgeEdge_SetNewMin( Y, X, Y, X );
764
signsA.setY( -signsA.getY() );
765
scalesA.setY( -scalesA.getY() );
767
distSqr = CustomEdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA,
768
matrixAB, matrixBA, signsA, signsB, scalesA, scalesB );
770
if ( distSqr < minDistSqr ) {
771
EdgeEdge_SetNewMin( Y, X, Y, X );
777
boxBoxDistance(vmVector3& normal, BoxPoint& boxPointA, BoxPoint& boxPointB,
778
PE_REF(Box) boxA, const vmTransform3 & transformA, PE_REF(Box) boxB,
779
const vmTransform3 & transformB,
780
float distanceThreshold)
783
identity = vmMatrix3::identity();
785
ident[0] = identity.getCol0();
786
ident[1] = identity.getCol1();
787
ident[2] = identity.getCol2();
789
// get relative transformations
791
vmTransform3 transformAB, transformBA;
792
vmMatrix3 matrixAB, matrixBA;
793
vmVector3 offsetAB, offsetBA;
795
transformAB = orthoInverse(transformA) * transformB;
796
transformBA = orthoInverse(transformAB);
798
matrixAB = transformAB.getUpper3x3();
799
offsetAB = transformAB.getTranslation();
800
matrixBA = transformBA.getUpper3x3();
801
offsetBA = transformBA.getTranslation();
803
vmMatrix3 absMatrixAB = absPerElem(matrixAB);
804
vmMatrix3 absMatrixBA = absPerElem(matrixBA);
806
// find separating axis with largest gap between projections
808
BoxSepAxisType axisType;
809
vmVector3 axisA(0.0f), axisB(0.0f);
811
int faceDimA = 0, faceDimB = 0, edgeDimA = 0, edgeDimB = 0;
815
vmVector3 gapsA = absPerElem(offsetAB) - boxA.mHalf - absMatrixAB * boxB.mHalf;
818
AaxisTest(1,Y,false);
819
AaxisTest(2,Z,false);
821
vmVector3 gapsB = absPerElem(offsetBA) - boxB.mHalf - absMatrixBA * boxA.mHalf;
827
// cross product axes
829
// ļæ½Oļæ½Ļļæ½ļæ½Oļæ½ĢĘļæ½ļæ½ĢĪļæ½
830
absMatrixAB += vmMatrix3(1.0e-5f);
831
absMatrixBA += vmMatrix3(1.0e-5f);
833
vmMatrix3 lsqrs, projOffset, projAhalf, projBhalf;
835
lsqrs.setCol0( mulPerElem( matrixBA.getCol2(), matrixBA.getCol2() ) +
836
mulPerElem( matrixBA.getCol1(), matrixBA.getCol1() ) );
837
lsqrs.setCol1( mulPerElem( matrixBA.getCol2(), matrixBA.getCol2() ) +
838
mulPerElem( matrixBA.getCol0(), matrixBA.getCol0() ) );
839
lsqrs.setCol2( mulPerElem( matrixBA.getCol1(), matrixBA.getCol1() ) +
840
mulPerElem( matrixBA.getCol0(), matrixBA.getCol0() ) );
842
projOffset.setCol0(matrixBA.getCol1() * offsetAB.getZ() - matrixBA.getCol2() * offsetAB.getY());
843
projOffset.setCol1(matrixBA.getCol2() * offsetAB.getX() - matrixBA.getCol0() * offsetAB.getZ());
844
projOffset.setCol2(matrixBA.getCol0() * offsetAB.getY() - matrixBA.getCol1() * offsetAB.getX());
846
projAhalf.setCol0(absMatrixBA.getCol1() * boxA.mHalf.getZ() + absMatrixBA.getCol2() * boxA.mHalf.getY());
847
projAhalf.setCol1(absMatrixBA.getCol2() * boxA.mHalf.getX() + absMatrixBA.getCol0() * boxA.mHalf.getZ());
848
projAhalf.setCol2(absMatrixBA.getCol0() * boxA.mHalf.getY() + absMatrixBA.getCol1() * boxA.mHalf.getX());
850
projBhalf.setCol0(absMatrixAB.getCol1() * boxB.mHalf.getZ() + absMatrixAB.getCol2() * boxB.mHalf.getY());
851
projBhalf.setCol1(absMatrixAB.getCol2() * boxB.mHalf.getX() + absMatrixAB.getCol0() * boxB.mHalf.getZ());
852
projBhalf.setCol2(absMatrixAB.getCol0() * boxB.mHalf.getY() + absMatrixAB.getCol1() * boxB.mHalf.getX());
854
vmMatrix3 gapsAxB = absPerElem(projOffset) - projAhalf - transpose(projBhalf);
856
CrossAxisTest(0,0,X);
857
CrossAxisTest(0,1,Y);
858
CrossAxisTest(0,2,Z);
859
CrossAxisTest(1,0,X);
860
CrossAxisTest(1,1,Y);
861
CrossAxisTest(1,2,Z);
862
CrossAxisTest(2,0,X);
863
CrossAxisTest(2,1,Y);
864
CrossAxisTest(2,2,Z);
866
// need to pick the face on each box whose normal best matches the separating axis.
867
// will transform vectors to be in the coordinate system of this face to simplify things later.
868
// for this, a permutation matrix can be used, which the next section computes.
870
int dimA[3], dimB[3];
872
if ( axisType == A_AXIS ) {
873
if ( dot(axisA,offsetAB) < 0.0f )
875
axisB = matrixBA * -axisA;
877
vmVector3 absAxisB = vmVector3(absPerElem(axisB));
879
if ( ( absAxisB[0] > absAxisB[1] ) && ( absAxisB[0] > absAxisB[2] ) )
881
else if ( absAxisB[1] > absAxisB[2] )
885
} else if ( axisType == B_AXIS ) {
886
if ( dot(axisB,offsetBA) < 0.0f )
888
axisA = matrixAB * -axisB;
890
vmVector3 absAxisA = vmVector3(absPerElem(axisA));
892
if ( ( absAxisA[0] > absAxisA[1] ) && ( absAxisA[0] > absAxisA[2] ) )
894
else if ( absAxisA[1] > absAxisA[2] )
900
if ( axisType == CROSS_AXIS ) {
901
if ( dot(axisA,offsetAB) < 0.0f )
903
axisB = matrixBA * -axisA;
905
vmVector3 absAxisA = vmVector3(absPerElem(axisA));
906
vmVector3 absAxisB = vmVector3(absPerElem(axisB));
911
if ( edgeDimA == 0 ) {
912
if ( absAxisA[1] > absAxisA[2] ) {
919
} else if ( edgeDimA == 1 ) {
920
if ( absAxisA[2] > absAxisA[0] ) {
928
if ( absAxisA[0] > absAxisA[1] ) {
937
if ( edgeDimB == 0 ) {
938
if ( absAxisB[1] > absAxisB[2] ) {
945
} else if ( edgeDimB == 1 ) {
946
if ( absAxisB[2] > absAxisB[0] ) {
954
if ( absAxisB[0] > absAxisB[1] ) {
964
dimA[0] = (faceDimA+1)%3;
965
dimA[1] = (faceDimA+2)%3;
967
dimB[0] = (faceDimB+1)%3;
968
dimB[1] = (faceDimB+2)%3;
971
vmMatrix3 aperm_col, bperm_col;
973
aperm_col.setCol0(ident[dimA[0]]);
974
aperm_col.setCol1(ident[dimA[1]]);
975
aperm_col.setCol2(ident[dimA[2]]);
977
bperm_col.setCol0(ident[dimB[0]]);
978
bperm_col.setCol1(ident[dimB[1]]);
979
bperm_col.setCol2(ident[dimB[2]]);
981
vmMatrix3 aperm_row, bperm_row;
983
aperm_row = transpose(aperm_col);
984
bperm_row = transpose(bperm_col);
986
// permute all box parameters to be in the face coordinate systems
988
vmMatrix3 matrixAB_perm = aperm_row * matrixAB * bperm_col;
989
vmMatrix3 matrixBA_perm = transpose(matrixAB_perm);
991
vmVector3 offsetAB_perm, offsetBA_perm;
993
offsetAB_perm = aperm_row * offsetAB;
994
offsetBA_perm = bperm_row * offsetBA;
996
vmVector3 halfA_perm, halfB_perm;
998
halfA_perm = aperm_row * boxA.mHalf;
999
halfB_perm = bperm_row * boxB.mHalf;
1001
// compute the vector between the centers of each face, in each face's coordinate frame
1003
vmVector3 signsA_perm, signsB_perm, scalesA_perm, scalesB_perm, faceOffsetAB_perm, faceOffsetBA_perm;
1005
signsA_perm = copySignPerElem(vmVector3(1.0f),aperm_row * axisA);
1006
signsB_perm = copySignPerElem(vmVector3(1.0f),bperm_row * axisB);
1007
scalesA_perm = mulPerElem( signsA_perm, halfA_perm );
1008
scalesB_perm = mulPerElem( signsB_perm, halfB_perm );
1010
faceOffsetAB_perm = offsetAB_perm + matrixAB_perm.getCol2() * scalesB_perm.getZ();
1011
faceOffsetAB_perm.setZ( faceOffsetAB_perm.getZ() - scalesA_perm.getZ() );
1013
faceOffsetBA_perm = offsetBA_perm + matrixBA_perm.getCol2() * scalesA_perm.getZ();
1014
faceOffsetBA_perm.setZ( faceOffsetBA_perm.getZ() - scalesB_perm.getZ() );
1016
if ( maxGap < 0.0f ) {
1017
// if boxes overlap, this will separate the faces for finding points of penetration.
1019
faceOffsetAB_perm -= aperm_row * axisA * maxGap * 1.01f;
1020
faceOffsetBA_perm -= bperm_row * axisB * maxGap * 1.01f;
1023
// for each vertex/face or edge/edge pair of the two faces, find the closest points.
1025
// these points each have an associated box feature (vertex, edge, or face). if each
1026
// point is in the external Voronoi region of the other's feature, they are the
1027
// closest points of the boxes, and the algorithm can exit.
1029
// the feature pairs are arranged so that in the general case, the first test will
1030
// succeed. degenerate cases (parallel faces) may require up to all tests in the
1033
// if for some reason no case passes the Voronoi test, the features with the minimum
1034
// distance are returned.
1036
vmPoint3 localPointA_perm, localPointB_perm;
1040
vmVector3 hA_perm( halfA_perm ), hB_perm( halfB_perm );
1042
localPointA_perm.setZ( scalesA_perm.getZ() );
1043
localPointB_perm.setZ( scalesB_perm.getZ() );
1044
scalesA_perm.setZ(0.0f);
1045
scalesB_perm.setZ(0.0f);
1047
int otherFaceDimA, otherFaceDimB;
1048
FeatureType featureA, featureB;
1050
if ( axisType == CROSS_AXIS ) {
1051
EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1052
otherFaceDimA, otherFaceDimB, featureA, featureB,
1053
hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1054
matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm,
1055
scalesA_perm, scalesB_perm, true );
1058
VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm,
1060
hA_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1061
matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, false );
1064
VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1066
hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1067
matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, false );
1070
} else if ( axisType == B_AXIS ) {
1071
VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1073
hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1074
matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, true );
1077
VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm,
1079
hA_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1080
matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, false );
1083
EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1084
otherFaceDimA, otherFaceDimB, featureA, featureB,
1085
hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1086
matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm,
1087
scalesA_perm, scalesB_perm, false );
1091
VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm,
1093
hA_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1094
matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, true );
1097
VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1099
hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1100
matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, false );
1103
EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm,
1104
otherFaceDimA, otherFaceDimB, featureA, featureB,
1105
hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm,
1106
matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm,
1107
scalesA_perm, scalesB_perm, false );
1112
// convert local points from face-local to box-local coordinate system
1115
boxPointA.localPoint = vmPoint3( aperm_col * vmVector3( localPointA_perm )) ;
1116
boxPointB.localPoint = vmPoint3( bperm_col * vmVector3( localPointB_perm )) ;
1119
// find which features of the boxes are involved.
1120
// the only feature pairs which occur in this function are VF, FV, and EE, even though the
1121
// closest points might actually lie on sub-features, as in a VF contact might be used for
1122
// what's actually a VV contact. this means some feature pairs could possibly seem distinct
1123
// from others, although their contact positions are the same. don't know yet whether this
1128
sA[0] = boxPointA.localPoint.getX() > 0.0f;
1129
sA[1] = boxPointA.localPoint.getY() > 0.0f;
1130
sA[2] = boxPointA.localPoint.getZ() > 0.0f;
1132
sB[0] = boxPointB.localPoint.getX() > 0.0f;
1133
sB[1] = boxPointB.localPoint.getY() > 0.0f;
1134
sB[2] = boxPointB.localPoint.getZ() > 0.0f;
1136
if ( featureA == F ) {
1137
boxPointA.setFaceFeature( dimA[2], sA[dimA[2]] );
1138
} else if ( featureA == E ) {
1139
boxPointA.setEdgeFeature( dimA[2], sA[dimA[2]], dimA[otherFaceDimA], sA[dimA[otherFaceDimA]] );
1141
boxPointA.setVertexFeature( sA[0], sA[1], sA[2] );
1144
if ( featureB == F ) {
1145
boxPointB.setFaceFeature( dimB[2], sB[dimB[2]] );
1146
} else if ( featureB == E ) {
1147
boxPointB.setEdgeFeature( dimB[2], sB[dimB[2]], dimB[otherFaceDimB], sB[dimB[otherFaceDimB]] );
1149
boxPointB.setVertexFeature( sB[0], sB[1], sB[2] );
1153
normal = transformA * axisA;
1155
if ( maxGap < 0.0f ) {
1158
return (sqrtf( minDistSqr ));