1
// Following code from Magic-Software (http://www.magic-software.com/)
2
// A bit modified for Opcode
4
static const float gs_fTolerance = 1e-05f;
6
static float OPC_PointTriangleSqrDist(const IceMaths::Point& point, const IceMaths::Point& p0, const IceMaths::Point& p1, const IceMaths::Point& p2)
9
IceMaths::Point TriEdge0 = p1 - p0;
10
IceMaths::Point TriEdge1 = p2 - p0;
12
IceMaths::Point kDiff = p0 - point;
13
float fA00 = TriEdge0.SquareMagnitude();
14
float fA01 = TriEdge0 | TriEdge1;
15
float fA11 = TriEdge1.SquareMagnitude();
16
float fB0 = kDiff | TriEdge0;
17
float fB1 = kDiff | TriEdge1;
18
float fC = kDiff.SquareMagnitude();
19
float fDet = fabsf(fA00*fA11 - fA01*fA01);
20
float fS = fA01*fB1-fA11*fB0;
21
float fT = fA01*fB0-fA00*fB1;
28
if(fT < 0.0f) // region 4
32
if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC;
33
else fSqrDist = fB0*(-fB0/fA00)+fC;
37
if(fB1 >= 0.0f) fSqrDist = fC;
38
else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC;
39
else fSqrDist = fB1*(-fB1/fA11)+fC;
44
if(fB1 >= 0.0f) fSqrDist = fC;
45
else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC;
46
else fSqrDist = fB1*(-fB1/fA11)+fC;
49
else if(fT < 0.0f) // region 5
51
if(fB0 >= 0.0f) fSqrDist = fC;
52
else if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC;
53
else fSqrDist = fB0*(-fB0/fA00)+fC;
57
// minimum at interior point
64
float fInvDet = 1.0f/fDet;
67
fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
73
float fTmp0, fTmp1, fNumer, fDenom;
75
if(fS < 0.0f) // region 2
81
fNumer = fTmp1 - fTmp0;
82
fDenom = fA00-2.0f*fA01+fA11;
85
fSqrDist = fA00+2.0f*fB0+fC;
91
fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
96
if(fTmp1 <= 0.0f) fSqrDist = fA11+2.0f*fB1+fC;
97
else if(fB1 >= 0.0f) fSqrDist = fC;
98
else fSqrDist = fB1*(-fB1/fA11)+fC;
101
else if(fT < 0.0f) // region 6
107
fNumer = fTmp1 - fTmp0;
108
fDenom = fA00-2.0f*fA01+fA11;
111
fSqrDist = fA11+2.0f*fB1+fC;
117
fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
122
if(fTmp1 <= 0.0f) fSqrDist = fA00+2.0f*fB0+fC;
123
else if(fB0 >= 0.0f) fSqrDist = fC;
124
else fSqrDist = fB0*(-fB0/fA00)+fC;
129
fNumer = fA11 + fB1 - fA01 - fB0;
132
fSqrDist = fA11+2.0f*fB1+fC;
136
fDenom = fA00-2.0f*fA01+fA11;
139
fSqrDist = fA00+2.0f*fB0+fC;
145
fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
150
return fabsf(fSqrDist);
153
static float OPC_SegmentSegmentSqrDist(const IceMaths::Segment& rkSeg0, const IceMaths::Segment& rkSeg1)
156
IceMaths::Point rkSeg0Direction = rkSeg0.ComputeDirection();
157
IceMaths::Point rkSeg1Direction = rkSeg1.ComputeDirection();
159
IceMaths::Point kDiff = rkSeg0.mP0 - rkSeg1.mP0;
160
float fA00 = rkSeg0Direction.SquareMagnitude();
161
float fA01 = -rkSeg0Direction.Dot(rkSeg1Direction);
162
float fA11 = rkSeg1Direction.SquareMagnitude();
163
float fB0 = kDiff.Dot(rkSeg0Direction);
164
float fC = kDiff.SquareMagnitude();
165
float fDet = fabsf(fA00*fA11-fA01*fA01);
167
float fB1, fS, fT, fSqrDist, fTmp;
169
if(fDet>=gs_fTolerance)
171
// line segments are not parallel
172
fB1 = -kDiff.Dot(rkSeg1Direction);
173
fS = fA01*fB1-fA11*fB0;
174
fT = fA01*fB0-fA00*fB1;
182
if(fT <= fDet) // region 0 (interior)
184
// minimum at two interior points of 3D lines
185
float fInvDet = 1.0f/fDet;
188
fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
190
else // region 3 (side)
193
if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC;
194
else if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp);
195
else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC;
198
else // region 7 (side)
200
if(fB0>=0.0f) fSqrDist = fC;
201
else if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC;
202
else fSqrDist = fB0*(-fB0/fA00)+fC;
209
if ( fT <= fDet ) // region 1 (side)
212
if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC;
213
else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
214
else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC;
216
else // region 2 (corner)
221
if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC;
222
else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC;
227
if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC;
228
else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
229
else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC;
233
else // region 8 (corner)
237
if(fB0>=0.0f) fSqrDist = fC;
238
else fSqrDist = fB0*(-fB0/fA00)+fC;
243
if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC;
244
else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
245
else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC;
254
if ( fT <= fDet ) // region 5 (side)
256
if(fB1>=0.0f) fSqrDist = fC;
257
else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC;
258
else fSqrDist = fB1*(-fB1/fA11)+fC;
260
else // region 4 (corner)
265
if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp);
266
else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC;
270
if(fB1>=0.0f) fSqrDist = fC;
271
else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC;
272
else fSqrDist = fB1*(-fB1/fA11)+fC;
276
else // region 6 (corner)
280
if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC;
281
else fSqrDist = fB0*(-fB0/fA00)+fC;
285
if(fB1>=0.0f) fSqrDist = fC;
286
else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC;
287
else fSqrDist = fB1*(-fB1/fA11)+fC;
294
// line segments are parallel
297
// direction vectors form an obtuse angle
302
else if ( -fB0 <= fA00 )
304
fSqrDist = fB0*(-fB0/fA00)+fC;
308
fB1 = -kDiff.Dot(rkSeg1Direction);
312
fSqrDist = fA00+fA11+fC+2.0f*(fA01+fB0+fB1);
317
fSqrDist = fA00+2.0f*fB0+fC+fT*(fA11*fT+2.0f*(fA01+fB1));
323
// direction vectors form an acute angle
326
fSqrDist = fA00+2.0f*fB0+fC;
328
else if ( fB0 <= 0.0f )
330
fSqrDist = fB0*(-fB0/fA00)+fC;
334
fB1 = -kDiff.Dot(rkSeg1Direction);
337
fSqrDist = fA11+2.0f*fB1+fC;
342
fSqrDist = fC+fT*(2.0f*fB1+fA11*fT);
347
return fabsf(fSqrDist);
350
inline_ float OPC_SegmentRaySqrDist(const IceMaths::Segment& rkSeg0, const IceMaths::Ray& rkSeg1)
352
return OPC_SegmentSegmentSqrDist(rkSeg0, IceMaths::Segment(rkSeg1.mOrig, rkSeg1.mOrig + rkSeg1.mDir));
355
static float OPC_SegmentTriangleSqrDist(const IceMaths::Segment& segment, const IceMaths::Point& p0, const IceMaths::Point& p1, const IceMaths::Point& p2)
358
const IceMaths::Point TriEdge0 = p1 - p0;
359
const IceMaths::Point TriEdge1 = p2 - p0;
361
const IceMaths::Point& rkSegOrigin = segment.GetOrigin();
362
IceMaths::Point rkSegDirection = segment.ComputeDirection();
364
IceMaths::Point kDiff = p0 - rkSegOrigin;
365
float fA00 = rkSegDirection.SquareMagnitude();
366
float fA01 = -rkSegDirection.Dot(TriEdge0);
367
float fA02 = -rkSegDirection.Dot(TriEdge1);
368
float fA11 = TriEdge0.SquareMagnitude();
369
float fA12 = TriEdge0.Dot(TriEdge1);
370
float fA22 = TriEdge1.Dot(TriEdge1);
371
float fB0 = -kDiff.Dot(rkSegDirection);
372
float fB1 = kDiff.Dot(TriEdge0);
373
float fB2 = kDiff.Dot(TriEdge1);
374
float fCof00 = fA11*fA22-fA12*fA12;
375
float fCof01 = fA02*fA12-fA01*fA22;
376
float fCof02 = fA01*fA12-fA02*fA11;
377
float fDet = fA00*fCof00+fA01*fCof01+fA02*fCof02;
379
IceMaths::Ray kTriSeg;
381
float fSqrDist, fSqrDist0;
383
if(fabsf(fDet)>=gs_fTolerance)
385
float fCof11 = fA00*fA22-fA02*fA02;
386
float fCof12 = fA02*fA01-fA00*fA12;
387
float fCof22 = fA00*fA11-fA01*fA01;
388
float fInvDet = 1.0f/fDet;
389
float fRhs0 = -fB0*fInvDet;
390
float fRhs1 = -fB1*fInvDet;
391
float fRhs2 = -fB2*fInvDet;
393
float fR = fCof00*fRhs0+fCof01*fRhs1+fCof02*fRhs2;
394
float fS = fCof01*fRhs0+fCof11*fRhs1+fCof12*fRhs2;
395
float fT = fCof02*fRhs0+fCof12*fRhs1+fCof22*fRhs2;
403
if ( fT < 0.0f ) // region 4m
405
// min on face s=0 or t=0 or r=0
407
kTriSeg.mDir = TriEdge1;
408
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
410
kTriSeg.mDir = TriEdge0;
411
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
412
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
413
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
414
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
418
// min on face s=0 or r=0
420
kTriSeg.mDir = TriEdge1;
421
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
422
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
423
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
426
else if ( fT < 0.0f ) // region 5m
428
// min on face t=0 or r=0
430
kTriSeg.mDir = TriEdge0;
431
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
432
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
433
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
438
fSqrDist = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
443
if ( fS < 0.0f ) // region 2m
445
// min on face s=0 or s+t=1 or r=0
447
kTriSeg.mDir = TriEdge1;
448
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
450
kTriSeg.mDir = TriEdge1-TriEdge0;
451
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
452
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
453
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
454
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
456
else if ( fT < 0.0f ) // region 6m
458
// min on face t=0 or s+t=1 or r=0
460
kTriSeg.mDir = TriEdge0;
461
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
463
kTriSeg.mDir = TriEdge1-TriEdge0;
464
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
465
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
466
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
467
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
471
// min on face s+t=1 or r=0
473
kTriSeg.mDir = TriEdge1-TriEdge0;
474
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
475
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
476
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
480
else if ( fR <= 1.0f )
486
if ( fT < 0.0f ) // region 4
488
// min on face s=0 or t=0
490
kTriSeg.mDir = TriEdge1;
491
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
493
kTriSeg.mDir = TriEdge0;
494
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
495
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
501
kTriSeg.mDir = TriEdge1;
502
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
505
else if ( fT < 0.0f ) // region 5
509
kTriSeg.mDir = TriEdge0;
510
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
514
// global minimum is interior, done
515
fSqrDist = fR*(fA00*fR+fA01*fS+fA02*fT+2.0f*fB0)
516
+fS*(fA01*fR+fA11*fS+fA12*fT+2.0f*fB1)
517
+fT*(fA02*fR+fA12*fS+fA22*fT+2.0f*fB2)
518
+kDiff.SquareMagnitude();
523
if ( fS < 0.0f ) // region 2
525
// min on face s=0 or s+t=1
527
kTriSeg.mDir = TriEdge1;
528
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
530
kTriSeg.mDir = TriEdge1-TriEdge0;
531
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
532
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
534
else if ( fT < 0.0f ) // region 6
536
// min on face t=0 or s+t=1
538
kTriSeg.mDir = TriEdge0;
539
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
541
kTriSeg.mDir = TriEdge1-TriEdge0;
542
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
543
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
549
kTriSeg.mDir = TriEdge1-TriEdge0;
550
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
560
if ( fT < 0.0f ) // region 4p
562
// min on face s=0 or t=0 or r=1
564
kTriSeg.mDir = TriEdge1;
565
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
567
kTriSeg.mDir = TriEdge0;
568
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
569
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
570
kPt = rkSegOrigin+rkSegDirection;
571
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
572
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
576
// min on face s=0 or r=1
578
kTriSeg.mDir = TriEdge1;
579
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
580
kPt = rkSegOrigin+rkSegDirection;
581
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
582
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
585
else if ( fT < 0.0f ) // region 5p
587
// min on face t=0 or r=1
589
kTriSeg.mDir = TriEdge0;
590
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
591
kPt = rkSegOrigin+rkSegDirection;
592
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
593
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
598
kPt = rkSegOrigin+rkSegDirection;
599
fSqrDist = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
604
if ( fS < 0.0f ) // region 2p
606
// min on face s=0 or s+t=1 or r=1
608
kTriSeg.mDir = TriEdge1;
609
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
611
kTriSeg.mDir = TriEdge1-TriEdge0;
612
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
613
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
614
kPt = rkSegOrigin+rkSegDirection;
615
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
616
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
618
else if ( fT < 0.0f ) // region 6p
620
// min on face t=0 or s+t=1 or r=1
622
kTriSeg.mDir = TriEdge0;
623
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
625
kTriSeg.mDir = TriEdge1-TriEdge0;
626
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
627
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
628
kPt = rkSegOrigin+rkSegDirection;
629
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
630
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
634
// min on face s+t=1 or r=1
636
kTriSeg.mDir = TriEdge1-TriEdge0;
637
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
638
kPt = rkSegOrigin+rkSegDirection;
639
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
640
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
647
// segment and triangle are parallel
649
kTriSeg.mDir = TriEdge0;
650
fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg);
652
kTriSeg.mDir = TriEdge1;
653
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
654
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
657
kTriSeg.mDir = TriEdge1 - TriEdge0;
658
fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg);
659
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
661
fSqrDist0 = OPC_PointTriangleSqrDist(rkSegOrigin, p0, p1, p2);
662
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
664
kPt = rkSegOrigin+rkSegDirection;
665
fSqrDist0 = OPC_PointTriangleSqrDist(kPt, p0, p1, p2);
666
if(fSqrDist0<fSqrDist) fSqrDist = fSqrDist0;
668
return fabsf(fSqrDist);
671
inline_ BOOL LSSCollider::LSSTriOverlap(const IceMaths::Point& vert0_, const IceMaths::Point& vert1_, const IceMaths::Point& vert2_)
673
// Applies the model's local scale
674
const IceMaths::Point vert0 = vert0_*mLocalScale;
675
const IceMaths::Point vert1 = vert1_*mLocalScale;
676
const IceMaths::Point vert2 = vert2_*mLocalScale;
678
mNbVolumePrimTests++;
680
float s2 = OPC_SegmentTriangleSqrDist(mSeg, vert0, vert1, vert2);
681
if(s2<mRadius2) return TRUE;