00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "TGLCamera.h"
00013 #include "TGLIncludes.h"
00014 #include "TGLBoundingBox.h"
00015 #include "TError.h"
00016 #include "TMath.h"
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 ClassImp(TGLCamera)
00039
00040 const Double_t TGLCamera::fgInterestBoxExpansion = 1.3;
00041 UInt_t TGLCamera::fgDollyDeltaSens = 500;
00042
00043
00044 TGLCamera::TGLCamera() :
00045 fExternalCenter(kFALSE),
00046 fFixDefCenter(kFALSE),
00047 fCenter(&fDefCenter),
00048 fNearClip(0), fFarClip(0),
00049 fDollyDefault(1.0), fDollyDistance(1.0),
00050 fVAxisMinAngle(0.01f),
00051 fCacheDirty(kTRUE),
00052 fTimeStamp (1),
00053 fProjM(), fModVM(), fClipM(),
00054 fViewport(0,0,100,100),
00055 fLargestSeen(0.0)
00056 {
00057
00058 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
00059 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
00060 }
00061 TGLVertex3 origin;
00062 fCamBase.Set(origin, TGLVector3(1, 0, 0), TGLVector3(0, 0, 1));
00063 }
00064
00065
00066 TGLCamera::TGLCamera(const TGLVector3 & hAxis, const TGLVector3 & vAxis) :
00067 fExternalCenter(kFALSE),
00068 fFixDefCenter(kFALSE),
00069 fCenter(&fDefCenter),
00070 fNearClip(0), fFarClip(0),
00071 fDollyDefault(1.0), fDollyDistance(1.0),
00072 fVAxisMinAngle(0.01f),
00073 fCacheDirty(kTRUE),
00074 fTimeStamp (1),
00075 fProjM(), fModVM(), fClipM(),
00076 fViewport(0,0,100,100),
00077 fLargestSeen(0.0)
00078 {
00079
00080 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
00081 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
00082 }
00083 TGLVertex3 origin;
00084 fCamBase.Set(origin, vAxis, hAxis);
00085 }
00086
00087
00088 TGLCamera::~TGLCamera()
00089 {
00090
00091 }
00092
00093
00094 void TGLCamera::SetViewport(const TGLRect & viewport)
00095 {
00096
00097
00098 fViewport = viewport;
00099 IncTimeStamp();
00100 }
00101
00102
00103 void TGLCamera::UpdateCache() const
00104 {
00105
00106 assert(fCacheDirty);
00107
00108 glGetDoublev(GL_PROJECTION_MATRIX, fProjM.Arr());
00109 glGetDoublev(GL_MODELVIEW_MATRIX, fModVM.Arr());
00110
00111
00112
00113 fClipM = fProjM;
00114 fClipM *= fModVM;
00115
00116
00117 fFrustumPlanes[kRight].Set(fClipM[ 3] - fClipM[ 0],
00118 fClipM[ 7] - fClipM[ 4],
00119 fClipM[11] - fClipM[ 8],
00120 fClipM[15] - fClipM[12]);
00121
00122
00123 fFrustumPlanes[kLeft].Set(fClipM[ 3] + fClipM[ 0],
00124 fClipM[ 7] + fClipM[ 4],
00125 fClipM[11] + fClipM[ 8],
00126 fClipM[15] + fClipM[12]);
00127
00128
00129 fFrustumPlanes[kBottom].Set(fClipM[ 3] + fClipM[ 1],
00130 fClipM[ 7] + fClipM[ 5],
00131 fClipM[11] + fClipM[ 9],
00132 fClipM[15] + fClipM[13]);
00133
00134
00135
00136 fFrustumPlanes[kTop].Set(fClipM[ 3] - fClipM[ 1],
00137 fClipM[ 7] - fClipM[ 5],
00138 fClipM[11] - fClipM[ 9],
00139 fClipM[15] - fClipM[13]);
00140
00141
00142 fFrustumPlanes[kFar].Set(fClipM[ 3] - fClipM[ 2],
00143 fClipM[ 7] - fClipM[ 6],
00144 fClipM[11] - fClipM[10],
00145 fClipM[15] - fClipM[14]);
00146
00147
00148 fFrustumPlanes[kNear].Set(fClipM[ 3] + fClipM[ 2],
00149 fClipM[ 7] + fClipM[ 6],
00150 fClipM[11] + fClipM[10],
00151 fClipM[15] + fClipM[14]);
00152
00153 fCacheDirty = kFALSE;
00154 }
00155
00156
00157 TGLBoundingBox TGLCamera::Frustum(Bool_t asBox) const
00158 {
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 if (fCacheDirty) {
00172 Error("TGLCamera::FrustumBox()", "cache dirty - must call Apply()");
00173 }
00174
00175
00176 TGLVertex3 vertex[8];
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 vertex[4] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kBottom], fFrustumPlanes[kLeft]).second;
00188 vertex[5] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kBottom], fFrustumPlanes[kRight]).second;
00189 vertex[6] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kTop], fFrustumPlanes[kRight]).second;
00190 vertex[7] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kTop], fFrustumPlanes[kLeft]).second;
00191
00192 if (asBox) {
00193
00194
00195 vertex[0] = fFrustumPlanes[kNear].NearestOn(vertex[4]);
00196 vertex[1] = fFrustumPlanes[kNear].NearestOn(vertex[5]);
00197 vertex[2] = fFrustumPlanes[kNear].NearestOn(vertex[6]);
00198 vertex[3] = fFrustumPlanes[kNear].NearestOn(vertex[7]);
00199 } else {
00200
00201
00202 vertex[0] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kBottom], fFrustumPlanes[kLeft]).second;
00203 vertex[1] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kBottom], fFrustumPlanes[kRight]).second;
00204 vertex[2] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kTop], fFrustumPlanes[kRight]).second;
00205 vertex[3] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kTop], fFrustumPlanes[kLeft]).second;
00206 }
00207
00208 return TGLBoundingBox(vertex);
00209 }
00210
00211
00212 TGLVertex3 TGLCamera::EyePoint() const
00213 {
00214
00215
00216 if (fCacheDirty) {
00217 Error("TGLPerspectiveCamera::FrustumBox()", "cache dirty - must call Apply()");
00218 }
00219
00220
00221
00222
00223
00224 return Intersection(fFrustumPlanes[kRight], fFrustumPlanes[kLeft], fFrustumPlanes[kTop]).second;
00225 }
00226
00227
00228 TGLVector3 TGLCamera::EyeDirection() const
00229 {
00230
00231
00232 if (fCacheDirty) {
00233 Error("TGLCamera::FrustumBox()", "cache dirty - must call Apply()");
00234 }
00235
00236 return fFrustumPlanes[kNear].Norm();
00237 }
00238
00239
00240 TGLVertex3 TGLCamera::FrustumCenter() const
00241 {
00242
00243
00244
00245
00246 if (fCacheDirty) {
00247 Error("TGLCamera::FrustumCenter()", "cache dirty - must call Apply()");
00248 }
00249 std::pair<Bool_t, TGLVertex3> nearBottomLeft = Intersection(fFrustumPlanes[kNear],
00250 fFrustumPlanes[kBottom],
00251 fFrustumPlanes[kLeft]);
00252 std::pair<Bool_t, TGLVertex3> farTopRight = Intersection(fFrustumPlanes[kFar],
00253 fFrustumPlanes[kTop],
00254 fFrustumPlanes[kRight]);
00255
00256 if (!nearBottomLeft.first || !farTopRight.first) {
00257 Error("TGLCamera::FrustumCenter()", "frustum planes invalid");
00258 return TGLVertex3(0.0, 0.0, 0.0);
00259 }
00260 return nearBottomLeft.second + (farTopRight.second - nearBottomLeft.second)/2.0;
00261 }
00262
00263
00264 EOverlap TGLCamera::FrustumOverlap(const TGLBoundingBox & box) const
00265 {
00266
00267
00268
00269 if (fCacheDirty) {
00270 Error("TGLCamera::FrustumOverlap()", "cache dirty - must call Apply()");
00271 }
00272
00273
00274
00275
00276
00277
00278
00279 Int_t planesInside = 0;
00280 for (Int_t planeIndex = 0; planeIndex < kPlanesPerFrustum; ++planeIndex) {
00281 EOverlap planeOverlap = box.Overlap(fFrustumPlanes[planeIndex]);
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 if ( planeOverlap == kOutside ) {
00292 return kOutside;
00293 } else if ( planeOverlap == kInside ) {
00294 planesInside++;
00295 }
00296 }
00297
00298 if ( planesInside == kPlanesPerFrustum ) {
00299 return kInside;
00300 } else {
00301 return kPartial;
00302 }
00303 }
00304
00305
00306 EOverlap TGLCamera::ViewportOverlap(const TGLBoundingBox & box) const
00307 {
00308
00309
00310
00311
00312 return ViewportRect(box).Overlap(fViewport);
00313 }
00314
00315
00316 TGLRect TGLCamera::ViewportRect(const TGLBoundingBox & box,
00317 const TGLBoundingBox::EFace face) const
00318 {
00319
00320
00321
00322 return ViewportRect(box, &face);
00323 }
00324
00325
00326 TGLRect TGLCamera::ViewportRect(const TGLBoundingBox & box,
00327 const TGLBoundingBox::EFace * face) const
00328 {
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 if (fCacheDirty) {
00345 Error("TGLCamera::ViewportSize()", "cache dirty - must call Apply()");
00346 }
00347
00348
00349
00350
00351
00352
00353 Double_t winX, winY, winZ;
00354 TGLRect screenRect;
00355
00356
00357
00358 UInt_t vertexCount;
00359 if (face) {
00360 vertexCount = box.FaceVertices(*face).size();
00361 } else {
00362 vertexCount = box.NumVertices();
00363 }
00364
00365 for (UInt_t i = 0; i < vertexCount; i++)
00366 {
00367 const TGLVertex3 & vertex = face ? box.Vertex(box.FaceVertices(*face).at(i)) :
00368 box.Vertex(i);
00369
00370 gluProject(vertex.X(), vertex.Y(), vertex.Z(),
00371 fModVM.CArr(), fProjM.CArr(), fViewport.CArr(),
00372 &winX, &winY, &winZ);
00373
00374 if (i == 0) {
00375 screenRect.SetCorner(static_cast<Int_t>(winX),static_cast<Int_t>(winY));
00376 } else {
00377 screenRect.Expand(static_cast<Int_t>(winX), static_cast<Int_t>(winY));
00378 }
00379 }
00380
00381 return screenRect;
00382 }
00383
00384
00385 TGLVertex3 TGLCamera::WorldToViewport(const TGLVertex3 & worldVertex,
00386 TGLMatrix* modviewMat) const
00387 {
00388
00389
00390
00391
00392
00393
00394
00395
00396 if (fCacheDirty) {
00397 Error("TGLCamera::WorldToViewport()", "cache dirty - must call Apply()");
00398 }
00399 TGLVertex3 viewportVertex;
00400 gluProject(worldVertex[0], worldVertex[1], worldVertex[2],
00401 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
00402 fProjM.CArr(), fViewport.CArr(),
00403 &viewportVertex[0], &viewportVertex[1], &viewportVertex[2]);
00404 return viewportVertex;
00405 }
00406
00407
00408 TGLVector3 TGLCamera::WorldDeltaToViewport(const TGLVertex3 & worldRef,
00409 const TGLVector3 & worldDelta) const
00410 {
00411
00412
00413
00414
00415
00416
00417
00418 if (fCacheDirty) {
00419 Error("TGLCamera::WorldToViewport()", "cache dirty - must call Apply()");
00420 }
00421 TGLVertex3 other = worldRef + worldDelta;
00422 TGLVertex3 v1 = WorldToViewport(worldRef);
00423 TGLVertex3 v2 = WorldToViewport(other);
00424 return v2 - v1;
00425 }
00426
00427
00428 TGLVertex3 TGLCamera::ViewportToWorld(const TGLVertex3 & viewportVertex,
00429 TGLMatrix* modviewMat) const
00430 {
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 if (fCacheDirty) {
00446 Error("TGLCamera::ViewportToWorld()", "cache dirty - must call Apply()");
00447 }
00448 TGLVertex3 worldVertex;
00449 gluUnProject(viewportVertex[0], viewportVertex[1], viewportVertex[2],
00450 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
00451 fProjM.CArr(), fViewport.CArr(),
00452 &worldVertex[0], &worldVertex[1], &worldVertex[2]);
00453 return worldVertex;
00454 }
00455
00456
00457 TGLLine3 TGLCamera::ViewportToWorld(Double_t viewportX, Double_t viewportY) const
00458 {
00459
00460
00461
00462
00463
00464
00465
00466
00467 if (fCacheDirty) {
00468 Error("TGLCamera::Viewport2DToWorldLine()", "cache dirty - must call Apply()");
00469 }
00470
00471 TGLVertex3 nearClipWorld = ViewportToWorld(TGLVertex3(viewportX, viewportY, 0.0));
00472 TGLVertex3 farClipWorld = ViewportToWorld(TGLVertex3(viewportX, viewportY, 1.0));
00473 return TGLLine3(nearClipWorld, farClipWorld - nearClipWorld);
00474 }
00475
00476
00477 TGLLine3 TGLCamera::ViewportToWorld(const TPoint & viewport) const
00478 {
00479
00480
00481
00482
00483
00484
00485
00486
00487 return ViewportToWorld(viewport.GetX(), viewport.GetY());
00488 }
00489
00490
00491 std::pair<Bool_t, TGLVertex3> TGLCamera::ViewportPlaneIntersection(Double_t viewportX, Double_t viewportY,
00492 const TGLPlane & worldPlane) const
00493 {
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 TGLLine3 worldLine = ViewportToWorld(viewportX, viewportY);
00507
00508
00509 return Intersection(worldPlane, worldLine, kTRUE );
00510 }
00511
00512
00513 std::pair<Bool_t, TGLVertex3> TGLCamera::ViewportPlaneIntersection(const TPoint & viewport,
00514 const TGLPlane & worldPlane) const
00515 {
00516
00517
00518
00519
00520
00521 return ViewportPlaneIntersection(viewport.GetX(), viewport.GetY(), worldPlane);
00522 }
00523
00524
00525 TGLVector3 TGLCamera::ViewportDeltaToWorld(const TGLVertex3 & worldRef, Double_t viewportXDelta,
00526 Double_t viewportYDelta, TGLMatrix* modviewMat) const
00527 {
00528
00529
00530
00531
00532
00533 if (fCacheDirty) {
00534 Error("TGLCamera::ViewportDeltaToWorld()", "cache dirty - must call Apply()");
00535 }
00536 TGLVertex3 winVertex = WorldToViewport(worldRef, modviewMat);
00537 winVertex.Shift(viewportXDelta, viewportYDelta, 0.0);
00538 return (ViewportToWorld(winVertex, modviewMat) - worldRef);
00539 }
00540
00541
00542 Bool_t TGLCamera::OfInterest(const TGLBoundingBox & box, Bool_t ignoreSize) const
00543 {
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 Bool_t interest = kFALSE;
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 if (fInterestBox.IsEmpty()) {
00584 if (box.Diagonal() >= fLargestSeen * 0.001) {
00585 if (box.Diagonal() > fLargestSeen) {
00586 fLargestSeen = box.Diagonal();
00587 }
00588 interest = kTRUE;
00589 }
00590 } else {
00591
00592
00593
00594
00595 if (box.IsEmpty()) {
00596 interest = kTRUE;
00597 } else {
00598 if (ignoreSize || box.Diagonal() / fInterestBox.Diagonal() > 0.0001)
00599 interest = fInterestBox.Overlap(box) != kOutside;
00600 }
00601 }
00602
00603 return interest;
00604 }
00605
00606
00607 Bool_t TGLCamera::UpdateInterest(Bool_t force)
00608 {
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 Bool_t exposedUpdate = kFALSE;
00623
00624
00625 TGLBoundingBox frustumBox = Frustum(kTRUE);
00626 TGLBoundingBox newInterestBox(frustumBox);
00627
00628
00629
00630
00631 TGLVector3 frustumExtents = frustumBox.Extents();
00632 Double_t minBoxLength = frustumExtents.Mag() * fgInterestBoxExpansion;
00633 newInterestBox.Scale(minBoxLength/frustumExtents[0], minBoxLength/frustumExtents[1], minBoxLength/frustumExtents[2]);
00634
00635
00636 Double_t volRatio = 0.0;
00637
00638
00639
00640 if (!fInterestBox.IsEmpty()) {
00641 volRatio = newInterestBox.Volume() / fInterestBox.Volume();
00642 }
00643
00644
00645
00646
00647
00648 if (volRatio > 8.0 || volRatio < 0.125 || fInterestBox.IsEmpty() ||
00649 fInterestBox.Overlap(frustumBox) != kInside || force) {
00650 fPreviousInterestBox = fInterestBox;
00651 fInterestBox = newInterestBox;
00652
00653
00654 if (fInterestBox.Overlap(frustumBox) != kInside) {
00655 Error("TGLCamera::UpdateInterest", "update interest box does not contain frustum");
00656 }
00657
00658 exposedUpdate = kTRUE;
00659
00660
00661 fInterestFrustum = Frustum(kFALSE);
00662 fInterestFrustumAsBox = frustumBox;
00663
00664 if (gDebug>2 || force) {
00665 Info("TGLCamera::UpdateInterest", "changed - volume ratio %f", volRatio );
00666 }
00667 }
00668
00669 return exposedUpdate;
00670 }
00671
00672
00673 void TGLCamera::ResetInterest()
00674 {
00675
00676 fInterestBox.SetEmpty();
00677
00678
00679
00680 fLargestSeen = 0.0;
00681 }
00682
00683
00684 Bool_t TGLCamera::AdjustAndClampVal(Double_t & val, Double_t min, Double_t max,
00685 Int_t screenShift, Int_t screenShiftRange,
00686 Bool_t mod1, Bool_t mod2) const
00687 {
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 if (screenShift == 0) {
00701 return kFALSE;
00702 }
00703
00704
00705 Double_t sens = val * static_cast<Double_t>(screenShift);
00706
00707 if (mod1) {
00708 sens *= 0.1;
00709 if (mod2) {
00710 sens *= 0.1;
00711 }
00712 } else {
00713 if (mod2) {
00714 sens *= 10.0;
00715 }
00716 }
00717
00718 Double_t oldVal = val;
00719 Double_t shift = sens / static_cast<Double_t>(screenShiftRange);
00720 val -= shift;
00721
00722 if (val < min) {
00723 val = min;
00724 }
00725 else if (val > max) {
00726 val = max;
00727 }
00728
00729 return val != oldVal;
00730 }
00731
00732
00733 Double_t TGLCamera::AdjustDelta(Double_t screenShift, Double_t deltaFactor,
00734 Bool_t mod1, Bool_t mod2) const
00735 {
00736
00737
00738
00739 if (screenShift == 0)
00740 return 0;
00741
00742
00743 Double_t sens = 1.0;
00744
00745 if (mod1) {
00746 sens *= 0.1;
00747 if (mod2) {
00748 sens *= 0.1;
00749 }
00750 } else {
00751 if (mod2) {
00752 sens *= 10.0;
00753 }
00754 }
00755
00756 return sens * deltaFactor * screenShift;
00757 }
00758
00759
00760 void TGLCamera::DrawDebugAids() const
00761 {
00762
00763
00764
00765
00766
00767
00768
00769
00770 glColor3d(1.0,0.0,0.0);
00771 fInterestFrustum.Draw();
00772
00773
00774 glColor3d(1.0,0.65,0.15);
00775 fInterestFrustumAsBox.Draw();
00776
00777
00778 glColor3d(0.0,0.0,1.0);
00779 fInterestBox.Draw();
00780
00781
00782 glColor3d(.8,.7,.6);
00783 fPreviousInterestBox.Draw();
00784
00785
00786
00787 TGLVertex3 start = EyePoint();
00788 TGLVertex3 end = start + EyeDirection();
00789 glColor3d(1.0,1.0,1.0);
00790 glBegin(GL_LINES);
00791 glVertex3dv(start.CArr());
00792 glVertex3dv(end.CArr());
00793 glEnd();
00794 }
00795
00796
00797 void TGLCamera::SetExternalCenter(Bool_t enable)
00798 {
00799
00800
00801 if (fExternalCenter == enable)
00802 return;
00803
00804 fExternalCenter = enable;
00805 if (fExternalCenter)
00806 fCenter = &fExtCenter;
00807 else
00808 fCenter = &fDefCenter;
00809
00810 TGLMatrix bt = fCamBase * fCamTrans;
00811 fCamBase.SetBaseVec(4, *fCenter);
00812 TGLMatrix binv = fCamBase; binv.Invert();
00813 fCamTrans = binv * bt;
00814
00815 IncTimeStamp();
00816 }
00817
00818
00819 void TGLCamera::SetCenterVec(Double_t x, Double_t y, Double_t z)
00820 {
00821
00822
00823 if (fExternalCenter)
00824 fExtCenter.Set(x, y, z);
00825 else
00826 fDefCenter.Set(x, y, z);
00827
00828 TGLMatrix bt = fCamBase * fCamTrans;
00829 fCamBase.SetBaseVec(4, *fCenter);
00830 TGLMatrix binv = fCamBase; binv.Invert();
00831 fCamTrans = binv * bt;
00832
00833 IncTimeStamp();
00834 }
00835
00836
00837 void TGLCamera::SetCenterVecWarp(Double_t x, Double_t y, Double_t z)
00838 {
00839
00840
00841
00842
00843 if (fExternalCenter)
00844 fExtCenter.Set(x, y, z);
00845 else
00846 fDefCenter.Set(x, y, z);
00847
00848 fCamBase.SetBaseVec(4, *fCenter);
00849
00850 IncTimeStamp();
00851 }
00852
00853
00854 Double_t TGLCamera::GetTheta() const
00855 {
00856
00857
00858 TGLVector3 fwd = fCamTrans.GetBaseVec(1);
00859 TGLVector3 zdir = fCamBase.GetBaseVec(3);
00860 fCamBase.RotateIP(fwd);
00861 return TMath::ACos(fwd*zdir);
00862 }
00863
00864
00865 Bool_t TGLCamera::Truck(Double_t xDelta, Double_t yDelta)
00866 {
00867
00868
00869
00870 if (xDelta != 0 || yDelta != 0)
00871 {
00872 fCamTrans.MoveLF(2, xDelta);
00873 fCamTrans.MoveLF(3, yDelta);
00874
00875 IncTimeStamp();
00876 return kTRUE;
00877 }
00878 else
00879 {
00880 return kFALSE;
00881 }
00882 }
00883
00884
00885 Bool_t TGLCamera::Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
00886 {
00887
00888
00889
00890
00891
00892 Double_t vRotate = AdjustDelta(xDelta, TMath::TwoPi() / fViewport.Width(), mod1, mod2);
00893 Double_t hRotate = AdjustDelta(yDelta, TMath::Pi() / fViewport.Height(), mod1, mod2);
00894
00895 return RotateRad(hRotate, vRotate);
00896 }
00897
00898
00899 Bool_t TGLCamera::RotateRad(Double_t hRotate, Double_t vRotate)
00900 {
00901
00902
00903 using namespace TMath;
00904 if (hRotate != 0.0)
00905 {
00906 TGLVector3 fwd = fCamTrans.GetBaseVec(1);
00907 TGLVector3 lft = fCamTrans.GetBaseVec(2);
00908 TGLVector3 up = fCamTrans.GetBaseVec(3);
00909 TGLVector3 pos = fCamTrans.GetTranslation();
00910
00911 TGLVector3 deltaT = pos - (pos*lft)*lft;
00912 Double_t deltaF = deltaT * fwd;
00913 Double_t deltaU = deltaT * up;
00914
00915
00916 TGLVector3 zdir = fCamBase.GetBaseVec(3);
00917 fCamBase.RotateIP(fwd);
00918 Double_t theta = ACos(fwd*zdir);
00919 if(theta+hRotate < fVAxisMinAngle)
00920 hRotate = fVAxisMinAngle - theta;
00921 else if(theta+hRotate > Pi() - fVAxisMinAngle)
00922 hRotate = Pi() - fVAxisMinAngle - theta;
00923
00924 fCamTrans.MoveLF(1, -deltaF);
00925 fCamTrans.MoveLF(3, -deltaU);
00926 fCamTrans.RotateLF(3, 1, hRotate);
00927 fCamTrans.MoveLF(3, deltaU);
00928 fCamTrans.MoveLF(1, deltaF);
00929 }
00930 if (vRotate != 0.0)
00931 {
00932 fCamTrans.RotatePF(1, 2, -vRotate);
00933 }
00934
00935 IncTimeStamp();
00936 return kTRUE;
00937 }
00938
00939
00940 Bool_t TGLCamera::Dolly(Int_t delta, Bool_t mod1, Bool_t mod2)
00941 {
00942
00943
00944
00945
00946
00947
00948
00949
00950 Double_t step = AdjustDelta(delta, fDollyDistance, mod1, mod2);
00951 if (step == 0)
00952 return kFALSE;
00953
00954 fCamTrans.MoveLF(1, -step);
00955
00956 IncTimeStamp();
00957 return kTRUE;
00958 }