00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stdpacs.h"
00025
00026 #include "nel/misc/hierarchical_timer.h"
00027
00028 #include "primitive_world_image.h"
00029 #include "move_primitive.h"
00030 #include "move_element.h"
00031
00032 using namespace NLMISC;
00033
00034
00035 namespace NLPACS
00036 {
00037
00038
00039
00040 CPrimitiveWorldImage::CPrimitiveWorldImage()
00041 {
00042
00043 for (uint i=0; i<4; i++)
00044 _MoveElement[i]=NULL;
00045
00046 _DynamicFlags=0;
00047 _BBXMin=-FLT_MAX;
00048 _BBXMax=-FLT_MAX;
00049 _BBYMin=-FLT_MAX;
00050 _BBYMax=-FLT_MAX;
00051 }
00052
00053
00054
00055 void CPrimitiveWorldImage::deleteIt (CMoveContainer &container, uint8 worldImage)
00056 {
00057
00058 for (uint i=0; i<4; i++)
00059 if (_MoveElement[i])
00060 removeMoveElement (i, container, worldImage);
00061 }
00062
00063
00064 void CPrimitiveWorldImage::copy (const CPrimitiveWorldImage& source)
00065 {
00066
00067 this->operator=(source);
00068
00069
00070 _DynamicFlags&=~InModifiedListFlag;
00071
00072
00073 for (uint i=0; i<4; i++)
00074 _MoveElement[i]=NULL;
00075 }
00076
00077
00078
00079 bool CPrimitiveWorldImage::evalCollision (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax, uint32 testTime,
00080 uint32 maxTestIteration, double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
00081 CMovePrimitive& otherPrimitive)
00082 {
00083
00084
00085
00086 if (( (primitive.getCollisionMaskInternal() & otherPrimitive.getOcclusionMaskInternal()) == 0) &&
00087 ( (primitive.getOcclusionMaskInternal() & otherPrimitive.getCollisionMaskInternal()) == 0))
00088 return false;
00089
00090
00091 if ( (!primitive.checkTestTime (testTime, maxTestIteration)) || (!otherPrimitive.checkTestTime (testTime, maxTestIteration)) )
00092 return false;
00093
00094
00095 firstContactTime=FLT_MAX;
00096 lastContactTime=-FLT_MAX;
00097
00098
00099 switch (primitive.getPrimitiveTypeInternal())
00100 {
00101
00102
00103 case UMovePrimitive::_2DOrientedBox:
00104 {
00105
00106 switch (otherPrimitive.getPrimitiveTypeInternal())
00107 {
00108
00109
00110 case UMovePrimitive::_2DOrientedBox:
00111
00112 return evalCollisionOBoverOB (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
00113
00114
00115 case UMovePrimitive::_2DOrientedCylinder:
00116
00117 return evalCollisionOBoverOC (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
00118
00119 default:
00120
00121 nlstop;
00122 }
00123 }
00124
00125
00126 case UMovePrimitive::_2DOrientedCylinder:
00127 {
00128
00129 switch (otherPrimitive.getPrimitiveTypeInternal())
00130 {
00131
00132
00133 case UMovePrimitive::_2DOrientedBox:
00134 {
00135
00136 bool collid=other.evalCollisionOBoverOC (*this, desc, timeMin, timeMax, firstContactTime, lastContactTime, otherPrimitive,
00137 primitive);
00138 if (collid)
00139 desc.XChgContactNormals ();
00140 return collid;
00141 }
00142
00143
00144 case UMovePrimitive::_2DOrientedCylinder:
00145
00146 return evalCollisionOCoverOC (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
00147
00148 default:
00149
00150 nlstop;
00151 }
00152 }
00153
00154 default:
00155
00156 nlstop;
00157 }
00158
00159 return false;
00160 }
00161
00162
00163
00164 const TCollisionSurfaceDescVector *CPrimitiveWorldImage::evalCollision (CGlobalRetriever &retriever, CCollisionSurfaceTemp& surfaceTemp,
00165 uint32 testTime, uint32 maxTestIteration, CMovePrimitive& primitive)
00166 {
00167
00168
00169
00170 if (!primitive.checkTestTime (testTime, maxTestIteration))
00171 return NULL;
00172
00173
00174 if (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox)
00175 {
00176
00177 CVector locI ((float)(_OBData.EdgeDirectionX[0]*primitive.getLength(0)/2.0), (float)(_OBData.EdgeDirectionY[0]*primitive.getLength(1)/2.0), 0);
00178
00179
00180 CVector locJ ((float)(_OBData.EdgeDirectionX[1]*primitive.getLength(0)/2.0), (float)(_OBData.EdgeDirectionY[1]*primitive.getLength(1)/2.0), 0);
00181
00182
00183 return retriever.testBBoxMove (_Position.getGlobalPos (), _DeltaPosition, locI, locJ, surfaceTemp);
00184 }
00185 else
00186 {
00187
00188 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00189
00190
00191
00192
00193 return retriever.testCylinderMove (_Position.getGlobalPos (), _DeltaPosition, primitive.getRadiusInternal(), surfaceTemp);
00194 }
00195 }
00196
00197
00198
00199 void CPrimitiveWorldImage::doMove (CGlobalRetriever &retriever, CCollisionSurfaceTemp& surfaceTemp, double originalMax, double finalMax, bool keepZ )
00200 {
00201 H_AUTO(NLPACS_PWI_Do_Move);
00202
00203
00204
00205 double ratio;
00206 if (finalMax!=originalMax)
00207 ratio=(finalMax-_InitTime)/(originalMax-_InitTime);
00208 else
00209 ratio=1;
00210
00211
00212 if (!keepZ)
00213 {
00214 _Position.setGlobalPos (retriever.doMove(_Position.getGlobalPos(), _DeltaPosition, (float)ratio, surfaceTemp, false), retriever);
00215 }
00216 else
00217 {
00218 _Position.setGlobalPosKeepZ(retriever.doMove(_Position.getGlobalPos(), _DeltaPosition, (float)ratio, surfaceTemp, false), retriever);
00219 }
00220
00221
00222
00223 _InitTime=finalMax;
00224 }
00225
00226
00227
00228 void CPrimitiveWorldImage::doMove (double timeMax)
00229 {
00230
00231
00232
00233 _Position.setPos (_Position.getPos ()+_Speed*(timeMax-_InitTime));
00234
00235
00236 _InitTime=timeMax;
00237 }
00238
00239
00240
00241 bool CPrimitiveWorldImage::evalCollisionOBoverOB (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
00242 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
00243 CMovePrimitive& otherPrimitive)
00244 {
00245
00246 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00247 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00248
00249
00250 bool find=false;
00251
00252
00253 desc.ContactTime=FLT_MAX;
00254
00255
00256 double _timeMax=-FLT_MAX;
00257
00258
00259 uint pt;
00260 uint seg;
00261 for (pt=0; pt<4; pt++)
00262 for (seg=0; seg<4; seg++)
00263 {
00264
00265 CCollisionDesc d;
00266 if ( evalCollisionPoverS (other, d, pt, seg, primitive, otherPrimitive) )
00267 {
00268
00269 find=true;
00270
00271
00272 if (d.ContactTime<desc.ContactTime)
00273 {
00274
00275 desc=d;
00276 }
00277
00278
00279 if (d.ContactTime>_timeMax)
00280 {
00281
00282 _timeMax=d.ContactTime;
00283 }
00284 }
00285 }
00286
00287
00288 for (pt=0; pt<4; pt++)
00289 for (seg=0; seg<4; seg++)
00290 {
00291
00292 CCollisionDesc d;
00293 if (other.evalCollisionPoverS (*this, d, pt, seg, primitive, otherPrimitive))
00294 {
00295
00296 find=true;
00297
00298
00299 if (d.ContactTime<desc.ContactTime)
00300 {
00301
00302 desc=d;
00303 }
00304
00305
00306 if (d.ContactTime>_timeMax)
00307 {
00308
00309 _timeMax=d.ContactTime;
00310 }
00311 }
00312 }
00313
00314 if (find)
00315 {
00316
00317 firstContactTime=desc.ContactTime;
00318 lastContactTime=_timeMax;
00319
00320
00321
00322
00323
00324
00325 if (timeMin > _timeMax)
00326
00327 return false;
00328
00329
00330 if (timeMax>desc.ContactTime)
00331 {
00332
00333 if (desc.ContactTime<timeMin)
00334 desc.ContactTime=timeMin;
00335
00336
00337 return true;
00338 }
00339 }
00340
00341
00342 return false;
00343 }
00344
00345
00346
00347 bool CPrimitiveWorldImage::evalCollisionOBoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
00348 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
00349 CMovePrimitive& otherPrimitive)
00350 {
00351
00352 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00353 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00354
00355
00356 bool find=false;
00357
00358
00359 desc.ContactTime=FLT_MAX;
00360
00361
00362 double _timeMax = -FLT_MAX;
00363
00364
00365 uint pt;
00366 for (pt=0; pt<4; pt++)
00367 {
00368
00369 CCollisionDesc d;
00370 double firstContactTime;
00371 double lastContactTime;
00372 if (evalCollisionPoverOC (other, d, pt, firstContactTime, lastContactTime, primitive, otherPrimitive))
00373 {
00374
00375 find=true;
00376
00377
00378 if (firstContactTime<desc.ContactTime)
00379 {
00380
00381 desc=d;
00382 }
00383
00384
00385 if (lastContactTime>_timeMax)
00386 {
00387
00388 _timeMax=lastContactTime;
00389 }
00390 }
00391 }
00392
00393
00394 uint seg;
00395 for (seg=0; seg<4; seg++)
00396 {
00397
00398 CCollisionDesc d;
00399 if (evalCollisionSoverOC (other, d, seg, primitive, otherPrimitive))
00400 {
00401
00402 find=true;
00403
00404
00405 if (d.ContactTime<desc.ContactTime)
00406 {
00407
00408 desc=d;
00409 }
00410
00411
00412 if (d.ContactTime>_timeMax)
00413 {
00414
00415 _timeMax=d.ContactTime;
00416 }
00417 }
00418 }
00419
00420 if (find)
00421 {
00422
00423 firstContactTime=desc.ContactTime;
00424 lastContactTime=_timeMax;
00425
00426
00427
00428
00429
00430
00431 if (timeMin > _timeMax)
00432
00433 return false;
00434
00435
00436 if (timeMax>desc.ContactTime)
00437 {
00438
00439 if (desc.ContactTime<timeMin)
00440 desc.ContactTime=timeMin;
00441
00442
00443 return true;
00444 }
00445 }
00446
00447
00448 return false;
00449 }
00450
00451
00452
00453 bool CPrimitiveWorldImage::evalCollisionPoverS (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numPoint, uint numSeg,
00454 CMovePrimitive& primitive, CMovePrimitive& otherPrimitive)
00455 {
00456
00457 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00458 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00459
00460
00461 const double normalSegX=other._OBData.EdgeDirectionY[numSeg];
00462 const double normalSegY=-other._OBData.EdgeDirectionX[numSeg];
00463
00464
00465 const double speedX=other._Speed.x-_Speed.x;
00466 const double speedY=other._Speed.y-_Speed.y;
00467
00468
00469 double dotProd= speedX*normalSegX + speedY*normalSegY;
00470
00471 if ( dotProd != 0 )
00472 {
00473
00474 double time= (normalSegX*(_OBData.PointPosX[numPoint] - other._OBData.PointPosX[numSeg]) +
00475 normalSegY*(_OBData.PointPosY[numPoint] - other._OBData.PointPosY[numSeg])) / dotProd;
00476
00477
00478 const double segPosX= other._OBData.PointPosX[numSeg] + other._Speed.x*time;
00479 const double segPosY= other._OBData.PointPosY[numSeg] + other._Speed.y*time;
00480
00481
00482 const double ptPosX= _OBData.PointPosX[numPoint] + _Speed.x*time;
00483 const double ptPosY= _OBData.PointPosY[numPoint] + _Speed.y*time;
00484
00485
00486 const double dirX= ptPosX - segPosX;
00487 const double dirY= ptPosY - segPosY;
00488
00489
00490 const double length= dirY*normalSegX - dirX*normalSegY;
00491
00492
00493 if ( ( length >= 0 ) && ( length <= otherPrimitive.getLength(numSeg&1) ) )
00494 {
00495
00496
00497
00498 const double pointSegZ=other._3dInitPosition.z;
00499 const double segPosZ= pointSegZ + other._Speed.z*time;
00500
00501
00502 const double pointZ=_3dInitPosition.z;
00503 const double ptPosZ= pointZ + _Speed.z*time;
00504
00505
00506 if ( (ptPosZ <= segPosZ + otherPrimitive.getHeightInternal()) && (ptPosZ + primitive.getHeightInternal() >= segPosZ) )
00507 {
00508
00509
00510
00511 desc.ContactTime=time;
00512
00513
00514 desc.ContactPosition.x=ptPosX;
00515 desc.ContactPosition.y=ptPosY;
00516 desc.ContactPosition.z=std::max (segPosZ, ptPosZ);
00517
00518
00519 desc.ContactNormal1.x=normalSegX;
00520 desc.ContactNormal1.y=normalSegY;
00521 desc.ContactNormal1.z=0;
00522 desc.ContactNormal0.x=-desc.ContactNormal1.x;
00523 desc.ContactNormal0.y=-desc.ContactNormal1.y;
00524 desc.ContactNormal0.z=0;
00525
00526
00527 return true;
00528 }
00529 }
00530 }
00531
00532
00533 return false;
00534 }
00535
00536
00537
00538 inline uint secondDegree (double a, double b, double c, double& s0, double& s1)
00539 {
00540 double d=b*b-4.f*a*c;
00541 if (d>0)
00542 {
00543
00544 d=(double)sqrt (d);
00545
00546
00547 a=0.5f/a;
00548
00549
00550 s0 = (-b-d)*a;
00551 s1 = (-b+d)*a;
00552
00553 return 2;
00554 }
00555 else if (d<0)
00556 {
00557
00558 return 0;
00559 }
00560 else
00561 {
00562
00563 s0 = -b/(2.f*a);
00564
00565 return 1;
00566 }
00567 }
00568
00569
00570
00571 bool CPrimitiveWorldImage::evalCollisionPoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numPoint,
00572 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
00573 CMovePrimitive& otherPrimitive)
00574 {
00575
00576 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00577 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 const double _Ax = _OBData.PointPosX[numPoint] - other._3dInitPosition.x;
00603 const double _Ay = _OBData.PointPosY[numPoint] - other._3dInitPosition.y;
00604 const double _Bx = _Speed.x - other._Speed.x;
00605 const double _By = _Speed.y - other._Speed.y;
00606
00607
00608 double s0, s1;
00609 double squareRadius=otherPrimitive.getRadiusInternal()*otherPrimitive.getRadiusInternal();
00610 uint numSolution=secondDegree (_Bx*_Bx+_By*_By, 2.f*(_Ax*_Bx+_Ay*_By), _Ax*_Ax+_Ay*_Ay-squareRadius, s0, s1);
00611 if (numSolution!=0)
00612 {
00613
00614 double time;
00615
00616
00617 if (numSolution==1)
00618 {
00619 firstContactTime=s0;
00620 lastContactTime=s0;
00621 }
00622 else
00623 {
00624
00625 if (s0<s1)
00626 {
00627 firstContactTime=s0;
00628 lastContactTime=s1;
00629 }
00630 else
00631 {
00632 firstContactTime=s1;
00633 lastContactTime=s0;
00634 }
00635 }
00636 time=firstContactTime;
00637
00638
00639 const double pointCylZ=other._3dInitPosition.z;
00640 const double cylPosZ= pointCylZ + other._Speed.z*time;
00641
00642
00643 const double pointZ=_3dInitPosition.z;
00644 const double ptPosZ= pointZ + _Speed.z*time;
00645
00646
00647 if ( (ptPosZ <= cylPosZ + otherPrimitive.getHeightInternal()) && (ptPosZ + primitive.getHeightInternal() >= cylPosZ) )
00648 {
00649
00650
00651
00652 desc.ContactTime=time;
00653
00654
00655 const double ptPosX= _OBData.PointPosX[numPoint] + _Speed.x*time;
00656 const double ptPosY= _OBData.PointPosY[numPoint] + _Speed.y*time;
00657
00658
00659 const double cylPosX= other._3dInitPosition.x + other._Speed.x*time;
00660 const double cylPosY= other._3dInitPosition.y + other._Speed.y*time;
00661
00662
00663 desc.ContactPosition.x=ptPosX;
00664 desc.ContactPosition.y=ptPosY;
00665 desc.ContactPosition.z=std::max (cylPosZ, ptPosZ);
00666
00667
00668 desc.ContactNormal1.x=ptPosX-cylPosX;
00669 desc.ContactNormal1.y=ptPosY-cylPosY;
00670 desc.ContactNormal1.z=0;
00671 desc.ContactNormal1.normalize ();
00672 desc.ContactNormal0.x=-desc.ContactNormal1.x;
00673 desc.ContactNormal0.y=-desc.ContactNormal1.y;
00674 desc.ContactNormal0.z=0;
00675
00676
00677 return true;
00678 }
00679 }
00680
00681
00682 return false;
00683 }
00684
00685
00686
00687 bool CPrimitiveWorldImage::evalCollisionSoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numSeg, CMovePrimitive& primitive,
00688 CMovePrimitive& otherPrimitive)
00689 {
00690
00691 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
00692 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00693
00694
00695 const double normalSegX=_OBData.EdgeDirectionY[numSeg];
00696 const double normalSegY=-_OBData.EdgeDirectionX[numSeg];
00697
00698
00699 const double speedX=other._Speed.x-_Speed.x;
00700 const double speedY=other._Speed.y-_Speed.y;
00701
00702
00703 double dotProd= speedX*normalSegX + speedY*normalSegY;
00704
00705 if ( dotProd !=0 )
00706 {
00707
00708 double time= (otherPrimitive.getRadiusInternal() + normalSegX*(_OBData.PointPosX[numSeg] - other._3dInitPosition.x ) +
00709 normalSegY*(_OBData.PointPosY[numSeg] - other._3dInitPosition.y ) ) / dotProd;
00710
00711
00712 const double segPosX= _OBData.PointPosX[numSeg] + _Speed.x*time;
00713 const double segPosY= _OBData.PointPosY[numSeg] + _Speed.y*time;
00714
00715
00716 const double cylPosX= other._3dInitPosition.x + _Speed.x*time;
00717 const double cylPosY= other._3dInitPosition.y + _Speed.y*time;
00718
00719
00720 const double contactX= cylPosX - normalSegX*otherPrimitive.getRadiusInternal();
00721 const double contactY= cylPosY - normalSegY*otherPrimitive.getRadiusInternal();
00722
00723
00724 const double dirX= contactX - segPosX;
00725 const double dirY= contactY - segPosY;
00726
00727
00728 const double length= dirY*normalSegX - dirX*normalSegY;
00729
00730
00731 if ( ( length >= 0 ) && ( length <= primitive.getLength (numSeg&1) ) )
00732 {
00733
00734
00735
00736 const double segPosZ= _3dInitPosition.z + _Speed.z*time;
00737
00738
00739 const double cylPosZ= other._3dInitPosition.z + other._Speed.z*time;
00740
00741
00742 if ( (cylPosZ <= segPosZ + primitive.getHeightInternal() ) && (cylPosZ + otherPrimitive.getHeightInternal() >= segPosZ) )
00743 {
00744
00745
00746
00747 desc.ContactTime=time;
00748
00749
00750 desc.ContactPosition.x=contactX;
00751 desc.ContactPosition.y=contactY;
00752 desc.ContactPosition.z=std::max (segPosZ, cylPosZ);
00753
00754
00755 desc.ContactNormal0.x=normalSegX;
00756 desc.ContactNormal0.y=normalSegY;
00757 desc.ContactNormal0.z=0;
00758
00759
00760 desc.ContactNormal1.x=contactX-cylPosX;
00761 desc.ContactNormal1.y=contactY-cylPosY;
00762 desc.ContactNormal1.z=0;
00763 desc.ContactNormal1.normalize ();
00764
00765
00766 return true;
00767 }
00768 }
00769 }
00770
00771
00772 return false;
00773 }
00774
00775
00776
00777
00778 bool CPrimitiveWorldImage::evalCollisionOCoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
00779 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
00780 CMovePrimitive& otherPrimitive)
00781 {
00782
00783 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00784 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810 const double _Ax = _3dInitPosition.x - other._3dInitPosition.x;
00811 const double _Ay = _3dInitPosition.y - other._3dInitPosition.y;
00812 const double _Bx = _Speed.x - other._Speed.x;
00813 const double _By = _Speed.y - other._Speed.y;
00814
00815
00816 double s0, s1;
00817 double radiusSquare=primitive.getRadiusInternal()+otherPrimitive.getRadiusInternal();
00818 radiusSquare*=radiusSquare;
00819 uint numSolution=secondDegree (_Bx*_Bx+_By*_By, 2.f*(_Ax*_Bx+_Ay*_By), _Ax*_Ax+_Ay*_Ay-radiusSquare, s0, s1);
00820 if (numSolution!=0)
00821 {
00822
00823 double _timeMin, _timeMax;
00824
00825
00826 if (numSolution==1)
00827 {
00828 _timeMin=s0;
00829 _timeMax=s0;
00830 }
00831 else
00832 {
00833
00834 if (s0>s1)
00835 {
00836 _timeMin=s1;
00837 _timeMax=s0;
00838 }
00839 else
00840 {
00841 _timeMin=s0;
00842 _timeMax=s1;
00843 }
00844 }
00845
00846
00847
00848
00849
00850 firstContactTime=_timeMin;
00851 lastContactTime=_timeMax;
00852
00853
00854 if ((timeMin<_timeMax)&&(_timeMin<timeMax))
00855 {
00856
00857 const double cyl0Time= _timeMin;
00858 const double pointCyl0Z=_3dInitPosition.z;
00859 const double cyl0PosZ= pointCyl0Z + _Speed.z*cyl0Time;
00860
00861
00862 const double cyl1Time= _timeMin;
00863 const double pointCyl1Z=other._3dInitPosition.z;
00864 const double cyl1PosZ= pointCyl1Z + other._Speed.z * cyl1Time;
00865
00866
00867 if ( (cyl0PosZ <= cyl1PosZ + otherPrimitive.getHeightInternal() ) && (cyl0PosZ + primitive.getHeightInternal() >= cyl1PosZ) )
00868 {
00869
00870
00871
00872 desc.ContactTime=std::max (_timeMin, timeMin);
00873
00874
00875 const double cyl0PosX= _3dInitPosition.x + _Speed.x*cyl0Time;
00876 const double cyl0PosY= _3dInitPosition.y + _Speed.y*cyl0Time;
00877
00878
00879 const double cyl1PosX= other._3dInitPosition.x + other._Speed.x*cyl1Time;
00880 const double cyl1PosY= other._3dInitPosition.y + other._Speed.y*cyl1Time;
00881
00882
00883 desc.ContactNormal0.x= cyl1PosX - cyl0PosX;
00884 desc.ContactNormal0.y= cyl1PosY - cyl0PosY;
00885 desc.ContactNormal0.z= 0;
00886 desc.ContactNormal0.normalize ();
00887
00888
00889 desc.ContactPosition.x= desc.ContactNormal0.x*primitive.getRadiusInternal() + cyl0PosX;
00890 desc.ContactPosition.y= desc.ContactNormal0.y*primitive.getRadiusInternal() + cyl0PosY;
00891 desc.ContactPosition.z= std::max (cyl0PosZ, cyl1PosZ);
00892
00893
00894 desc.ContactNormal1.x= -desc.ContactNormal0.x;
00895 desc.ContactNormal1.y= -desc.ContactNormal0.y;
00896 desc.ContactNormal1.z= 0;
00897
00898
00899 return true;
00900 }
00901 }
00902 }
00903
00904
00905 return false;
00906 }
00907
00908
00909
00910 void CPrimitiveWorldImage::precalcPos (CMovePrimitive &primitive)
00911 {
00912
00913 uint type=primitive.getPrimitiveTypeInternal();
00914
00915
00916 if (type==UMovePrimitive::_2DOrientedBox)
00917 {
00918
00919 double cosinus=(double)cos(_OBData.Orientation);
00920 double sinus=(double)sin(_OBData.Orientation);
00921
00922
00923 double halfWidth=primitive.getLength (0)/2;
00924 double halfDepth=primitive.getLength (1)/2;
00925
00926
00927 _OBData.PointPosX[0]=cosinus*(-halfWidth)-sinus*(-halfDepth)+_3dInitPosition.x;
00928 _OBData.PointPosY[0]=sinus*(-halfWidth)+cosinus*(-halfDepth)+_3dInitPosition.y;
00929
00930
00931 _OBData.PointPosX[1]=cosinus*halfWidth-sinus*(-halfDepth)+_3dInitPosition.x;
00932 _OBData.PointPosY[1]=sinus*halfWidth+cosinus*(-halfDepth)+_3dInitPosition.y;
00933
00934
00935 _OBData.PointPosX[2]=cosinus*halfWidth-sinus*halfDepth+_3dInitPosition.x;
00936 _OBData.PointPosY[2]=sinus*halfWidth+cosinus*halfDepth+_3dInitPosition.y;
00937
00938
00939 _OBData.PointPosX[3]=cosinus*(-halfWidth)-sinus*halfDepth+_3dInitPosition.x;
00940 _OBData.PointPosY[3]=sinus*(-halfWidth)+cosinus*halfDepth+_3dInitPosition.y;
00941
00942
00943 double length0 = (primitive.getLength(0)==0)? 0.001 : primitive.getLength(0);
00944 double length1 = (primitive.getLength(1)==0)? 0.001 : primitive.getLength(1);
00945 double oneOverLength[2]= { 1 / length0, 1 / length1 };
00946
00947
00948 uint i;
00949 for (i=0; i<4; i++)
00950 {
00951
00952 uint next=(i+1)&3;
00953 double oneOver=oneOverLength[i&1];
00954
00955
00956 _OBData.EdgeDirectionX[i]=(_OBData.PointPosX[next] - _OBData.PointPosX[i])*oneOver;
00957 _OBData.EdgeDirectionY[i]=(_OBData.PointPosY[next] - _OBData.PointPosY[i])*oneOver;
00958 }
00959 }
00960 else
00961 {
00962
00963 nlassert (type==UMovePrimitive::_2DOrientedCylinder);
00964 }
00965 }
00966
00967
00968
00969 void CPrimitiveWorldImage::precalcBB (double beginTime, double endTime, CMovePrimitive &primitive)
00970 {
00971
00972 uint type=primitive.getPrimitiveTypeInternal();
00973
00974
00975 if (type==UMovePrimitive::_2DOrientedBox)
00976 {
00977
00978 sint orient= (sint)(256.f*_OBData.Orientation/(2.f*NLMISC::Pi));
00979 orient&=0xff;
00980 orient>>=6;
00981 nlassert (orient>=0);
00982 nlassert (orient<4);
00983
00984
00985 _BBXMin=FLT_MAX;
00986 _BBYMin=FLT_MAX;
00987 _BBXMax=-FLT_MAX;
00988 _BBYMax=-FLT_MAX;
00989
00990 for (uint i=0; i<4; i++)
00991 {
00992 if (_OBData.PointPosX[i]<_BBXMin)
00993 _BBXMin=_OBData.PointPosX[i];
00994 if (_OBData.PointPosX[i]>_BBXMax)
00995 _BBXMax=_OBData.PointPosX[i];
00996 if (_OBData.PointPosY[i]<_BBYMin)
00997 _BBYMin=_OBData.PointPosY[i];
00998 if (_OBData.PointPosY[i]>_BBYMax)
00999 _BBYMax=_OBData.PointPosY[i];
01000 }
01001 _BBXMin=std::min (std::min (_BBXMin, _BBXMin+endTime*_Speed.x), _BBXMin+beginTime*_Speed.x);
01002 _BBXMax=std::max (std::max (_BBXMax, _BBXMax+endTime*_Speed.x), _BBXMax+beginTime*_Speed.x);
01003 _BBYMin=std::min (std::min (_BBYMin, _BBYMin+endTime*_Speed.y), _BBYMin+beginTime*_Speed.y);
01004 _BBYMax=std::max (std::max (_BBYMax, _BBYMax+endTime*_Speed.y), _BBYMax+beginTime*_Speed.y);
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019 }
01020 else
01021 {
01022
01023 nlassert (type==UMovePrimitive::_2DOrientedCylinder);
01024
01025
01026 _BBXMin= _3dInitPosition.x + _Speed.x*beginTime;
01027 _BBXMax= _3dInitPosition.x + _Speed.x*endTime;
01028 if (_BBXMin>_BBXMax)
01029 {
01030 double tmp=_BBXMin;
01031 _BBXMin=_BBXMax;
01032 _BBXMax=tmp;
01033 }
01034 _BBXMin-=primitive.getRadiusInternal();
01035 _BBXMax+=primitive.getRadiusInternal();
01036
01037
01038 _BBYMin= _3dInitPosition.y + _Speed.y*beginTime;
01039 _BBYMax= _3dInitPosition.y + _Speed.y*endTime;
01040 if (_BBYMin>_BBYMax)
01041 {
01042 double tmp=_BBYMin;
01043 _BBYMin=_BBYMax;
01044 _BBYMax=tmp;
01045 }
01046 _BBYMin-=primitive.getRadiusInternal();
01047 _BBYMax+=primitive.getRadiusInternal();
01048 }
01049
01050
01051 _DeltaPosition=_Speed*(endTime-beginTime);
01052 }
01053
01054
01055
01056 void CPrimitiveWorldImage::addMoveElement (CMoveCell& cell, uint16 x, uint16 y, double centerX, double , CMovePrimitive *primitive,
01057 CMoveContainer &container, uint8 worldImage)
01058 {
01059
01060 uint slot;
01061 for (slot=0; slot<4; slot++)
01062 {
01063
01064 if (_MoveElement[slot]==NULL)
01065 {
01066
01067 double cx=(_BBXMin+_BBXMax)/2.f;
01068
01069
01070 _MoveElement[slot]=container.allocateMoveElement ();
01071 _MoveElement[slot]->Primitive=primitive;
01072 _MoveElement[slot]->X=x;
01073 _MoveElement[slot]->Y=y;
01074
01075
01076 if (cx<centerX)
01077
01078 cell.linkFirstX (_MoveElement[slot]);
01079 else
01080
01081 cell.linkLastX (_MoveElement[slot]);
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092 cell.updateSortedLists (_MoveElement[slot], worldImage);
01093
01094
01095 break;
01096 }
01097 }
01098 }
01099
01100
01101
01102 void CPrimitiveWorldImage::addMoveElementendOfList (CMoveCell& cell, uint16 x, uint16 y, CMovePrimitive *primitive,
01103 CMoveContainer &container)
01104 {
01105
01106 uint slot;
01107 for (slot=0; slot<4; slot++)
01108 {
01109
01110 if (_MoveElement[slot]==NULL)
01111 {
01112
01113 _MoveElement[slot]=container.allocateMoveElement ();
01114 _MoveElement[slot]->Primitive=primitive;
01115 _MoveElement[slot]->X=x;
01116 _MoveElement[slot]->Y=y;
01117
01118
01119 cell.linkLastX (_MoveElement[slot]);
01120
01121
01122 break;
01123 }
01124 }
01125 }
01126
01127
01128
01129 void CPrimitiveWorldImage::removeMoveElement (uint i, CMoveContainer &container, uint8 worldImage)
01130 {
01131
01132 nlassert (i<4);
01133 nlassert (_MoveElement[i]!=NULL);
01134
01135
01136 container.unlinkMoveElement (_MoveElement[i], worldImage);
01137
01138
01139 container.freeMoveElement (_MoveElement[i]);
01140
01141
01142 _MoveElement[i]=NULL;
01143 }
01144
01145
01146
01147 void CPrimitiveWorldImage::checkSortedList (uint8 worldImage)
01148 {
01149
01150 for (uint i=0; i<4; i++)
01151 {
01152
01153 if (_MoveElement[i])
01154 {
01155 if (_MoveElement[i]->PreviousX)
01156 nlassertonce (_MoveElement[i]->PreviousX->Primitive->getWorldImage(worldImage)->_BBXMin <= _BBXMin);
01157 if (_MoveElement[i]->NextX)
01158 nlassertonce (_BBXMin <= _MoveElement[i]->NextX->Primitive->getWorldImage(worldImage)->_BBXMin);
01159 }
01160 }
01161 }
01162
01163
01164
01165 void CPrimitiveWorldImage::reaction (CPrimitiveWorldImage& second, const CCollisionDesc& desc, CGlobalRetriever* retriever,
01166 CCollisionSurfaceTemp& surfaceTemp, bool collision, CMovePrimitive &primitive,
01167 CMovePrimitive &otherPrimitive, CMoveContainer *container, uint8 worldImage, uint8 secondWorldImage,
01168 bool secondConst)
01169 {
01170
01171
01172
01173 UMovePrimitive::TReaction firstReaction=primitive.getReactionTypeInternal();
01174 UMovePrimitive::TReaction secondReaction=otherPrimitive.getReactionTypeInternal();
01175
01176
01177 collision = collision && (primitive.isObstacle ()) && (otherPrimitive.isObstacle ());
01178
01179
01180 float mass0 = primitive.getMass ();
01181 float mass1 = otherPrimitive.getMass ();
01182
01183
01184 double projSpeed0 = desc.ContactNormal1 * _Speed;
01185 double projSpeed1 = desc.ContactNormal0 * second._Speed;
01186 double energySum = (- mass0 * projSpeed0 - mass1 * projSpeed1 ) / 2.0;
01187
01188
01189 CVectorD collisionPosition=_3dInitPosition;
01190 collisionPosition+=_Speed*desc.ContactTime;
01191
01192
01193 CVectorD newSpeed;
01194
01195
01196 if (collision)
01197 {
01198 switch (firstReaction)
01199 {
01200 case UMovePrimitive::Slide:
01201
01202 newSpeed=_Speed - projSpeed0 * desc.ContactNormal1;
01203
01204
01205 newSpeed+=( primitive.getAttenuation()*energySum / mass0 ) * desc.ContactNormal1;
01206 break;
01207 case UMovePrimitive::Reflexion:
01208
01209 newSpeed=_Speed - projSpeed0 * desc.ContactNormal1;
01210
01211
01212 newSpeed+=( primitive.getAttenuation()*energySum / mass0 ) * desc.ContactNormal1;
01213 break;
01214 case UMovePrimitive::Stop:
01215 newSpeed.set (0,0,0);
01216 break;
01217 case UMovePrimitive::DoNothing:
01218 newSpeed=_Speed;
01219 break;
01220 default: break;
01221 }
01222
01223
01224 setSpeed (newSpeed, container, &primitive, worldImage);
01225
01226
01227 if (retriever)
01228 {
01229
01230 double deltaDist= _DeltaPosition.norm();
01231 double deltaTime;
01232 if(deltaDist<0.000001)
01233 deltaTime= 0;
01234 else
01235 deltaTime=(collisionPosition-_Position.getPos ()).norm()/deltaDist;
01236 nlassert (deltaTime>=0);
01237 nlassert (deltaTime<=1);
01238
01239 UGlobalPosition newPosition = retriever->doMove (_Position.getGlobalPos (), _DeltaPosition,
01240 (float)deltaTime, surfaceTemp, true);
01241
01242
01243 _Position.setGlobalPos (newPosition, *retriever);
01244
01245
01246 _3dInitPosition = _Position.getPos() - newSpeed * desc.ContactTime;
01247
01248
01249 _InitTime = desc.ContactTime;
01250 }
01251 else
01252 {
01253
01254 _Position.setPos (collisionPosition);
01255
01256
01257 _3dInitPosition = collisionPosition - newSpeed * desc.ContactTime;
01258
01259
01260 _InitTime = desc.ContactTime;
01261 }
01262
01263
01264 dirtPos (container, &primitive, worldImage);
01265
01266
01267
01268
01269 if (!secondConst)
01270 {
01271
01272 collisionPosition=second._3dInitPosition;
01273 collisionPosition+=second._Speed * desc.ContactTime;
01274
01275
01276 switch (secondReaction)
01277 {
01278 case UMovePrimitive::Slide:
01279
01280 newSpeed=second._Speed - projSpeed1 * desc.ContactNormal0;
01281
01282
01283 newSpeed+=( otherPrimitive.getAttenuation()*energySum / mass1 ) * desc.ContactNormal1;
01284 break;
01285 case UMovePrimitive::Reflexion:
01286
01287 newSpeed=second._Speed - projSpeed1 * desc.ContactNormal0;
01288
01289
01290 newSpeed+=( otherPrimitive.getAttenuation()*energySum / mass1 ) * desc.ContactNormal0;
01291 break;
01292 case UMovePrimitive::Stop:
01293 newSpeed.set (0,0,0);
01294 break;
01295 case UMovePrimitive::DoNothing:
01296 newSpeed=second._Speed;
01297 break;
01298 default: break;
01299 }
01300
01301
01302 second.setSpeed (newSpeed, container, &otherPrimitive, secondWorldImage);
01303
01304
01305 if (retriever)
01306 {
01307
01308 double deltaDist= second._DeltaPosition.norm();
01309 double deltaTime;
01310 if(deltaDist==0)
01311 deltaTime= 0;
01312 else
01313 deltaTime=(collisionPosition-second._Position.getPos ()).norm()/deltaDist;
01314 clamp (deltaTime, 0.0, 1.0);
01315
01316 UGlobalPosition newPosition = retriever->doMove (second._Position.getGlobalPos (), second._DeltaPosition,
01317 (float)deltaTime, surfaceTemp, true);
01318
01319
01320 second._Position.setGlobalPos (newPosition, *retriever);
01321
01322
01323 second._3dInitPosition = second._Position.getPos() - newSpeed * desc.ContactTime;
01324
01325
01326 second._InitTime = desc.ContactTime;
01327 }
01328 else
01329 {
01330
01331 second._Position.setPos (collisionPosition);
01332
01333
01334 second._3dInitPosition = collisionPosition - newSpeed * desc.ContactTime;
01335
01336
01337 second._InitTime = desc.ContactTime;
01338 }
01339
01340
01341 second.dirtPos (container, &otherPrimitive, secondWorldImage);
01342 }
01343 }
01344 }
01345
01346
01347
01348 void CPrimitiveWorldImage::reaction (const CCollisionSurfaceDesc& surfaceDesc, const UGlobalPosition& globalPosition,
01349 CGlobalRetriever& retriever, double , double dt, CMovePrimitive &primitive, CMoveContainer &container,
01350 uint8 worldImage)
01351 {
01352
01353
01354
01355 uint32 type=primitive.getReactionTypeInternal();
01356
01357
01358 _Position.setGlobalPos (globalPosition, retriever);
01359
01360
01361 if ((type==UMovePrimitive::Reflexion)||(type==UMovePrimitive::Slide))
01362 {
01363
01364 if (type==UMovePrimitive::Slide)
01365 {
01366
01367 _Speed-= surfaceDesc.ContactNormal*(surfaceDesc.ContactNormal*_Speed-NELPACS_DIST_BACK/(dt-surfaceDesc.ContactTime));
01368 }
01369
01370
01371 if (type==UMovePrimitive::Reflexion)
01372 {
01373
01374 double speedProj=surfaceDesc.ContactNormal*_Speed;
01375 _Speed-=surfaceDesc.ContactNormal*(speedProj+speedProj*primitive.getAttenuation()-NELPACS_DIST_BACK/(dt-surfaceDesc.ContactTime));
01376 }
01377 }
01378 else
01379 {
01380
01381 if (type==UMovePrimitive::Stop)
01382 {
01383 _Speed.set (0,0,0);
01384 }
01385 }
01386
01387
01388 double contactTime=surfaceDesc.ContactTime;
01389
01390
01391 _3dInitPosition = _Position.getPos() - _Speed * contactTime;
01392
01393
01394 _InitTime=contactTime;
01395
01396
01397 dirtPos (&container, &primitive, worldImage);
01398 }
01399
01400
01401
01402 void CPrimitiveWorldImage::setGlobalPosition (const UGlobalPosition& pos, CMoveContainer& container, CMovePrimitive &primitive, uint8 worldImage)
01403 {
01404
01405 nlassert (dynamic_cast<const CMoveContainer*>(&container));
01406 const CMoveContainer *cont=(const CMoveContainer*)&container;
01407
01408 if (!cont->getGlobalRetriever()) return;
01409
01410 nlassert (cont->getGlobalRetriever());
01411
01412
01413 _Position.setGlobalPos (pos, *cont->getGlobalRetriever());
01414
01415
01416 _3dInitPosition = _Position.getPos ();
01417 _InitTime = 0;
01418
01419
01420 _Speed=CVector::Null;
01421
01422
01423 dirtPos (&container, &primitive, worldImage);
01424 }
01425
01426
01427
01428 void CPrimitiveWorldImage::setGlobalPosition (const NLMISC::CVectorD& pos, CMoveContainer& container, CMovePrimitive &primitive, uint8 worldImage, bool keepZ , UGlobalPosition::TType type )
01429 {
01430
01431 nlassert (dynamic_cast<const CMoveContainer*>(&container));
01432 const CMoveContainer *cont=(const CMoveContainer*)&container;
01433
01434
01435 CGlobalRetriever *retriever=cont->getGlobalRetriever();
01436
01437
01438 if (retriever)
01439 {
01440
01441
01442
01443
01444 UGlobalPosition globalPosition=retriever->retrievePosition (pos, 1.0e10, type);
01445
01446 if (keepZ)
01447 {
01448
01449 _Position.setPos (pos);
01450
01451
01452 _Position.setGlobalPosKeepZ (globalPosition, *retriever);
01453 }
01454 else
01455 {
01456
01457 _Position.setGlobalPos (globalPosition, *retriever);
01458 }
01459 }
01460 else
01461 {
01462
01463 _Position.setPos (pos);
01464 }
01465
01466
01467 _3dInitPosition = _Position.getPos ();
01468 _InitTime = 0;
01469
01470
01471 _Speed=CVector::Null;
01472
01473
01474 dirtPos (&container, &primitive, worldImage);
01475 }
01476
01477
01478
01479 void CPrimitiveWorldImage::move (const NLMISC::CVectorD& speed, CMoveContainer& container, CMovePrimitive &primitive, uint8 worldImage)
01480 {
01481
01482 setSpeed (speed, &container, &primitive, worldImage);
01483
01484
01485 _3dInitPosition = _Position.getPos ();
01486
01487
01488 _InitTime = 0;
01489
01490
01491 dirtPos (&container, &primitive, worldImage);
01492 }
01493
01494
01495
01496
01497 }