38 const Double_t TGLCamera::fgInterestBoxExpansion = 1.3;
39 UInt_t TGLCamera::fgDollyDeltaSens = 500;
44 TGLCamera::TGLCamera() :
45 fExternalCenter(kFALSE),
46 fFixDefCenter(kFALSE),
47 fWasArcBalled(kFALSE),
49 fNearClip(0), fFarClip(0),
50 fDollyDefault(1.0), fDollyDistance(1.0),
51 fVAxisMinAngle(0.01f),
54 fProjM(), fModVM(), fClipM(),
55 fViewport(0,0,100,100),
58 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
59 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
62 fCamBase.Set(origin, TGLVector3(1, 0, 0), TGLVector3(0, 0, 1));
68 TGLCamera::TGLCamera(
const TGLVector3 & hAxis,
const TGLVector3 & vAxis) :
69 fExternalCenter(kFALSE),
70 fFixDefCenter(kFALSE),
71 fWasArcBalled(kFALSE),
73 fNearClip(0), fFarClip(0),
74 fDollyDefault(1.0), fDollyDistance(1.0),
75 fVAxisMinAngle(0.01f),
78 fProjM(), fModVM(), fClipM(),
79 fViewport(0,0,100,100),
82 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
83 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
86 fCamBase.Set(origin, vAxis, hAxis);
92 TGLCamera::~TGLCamera()
99 void TGLCamera::SetViewport(
const TGLRect & viewport)
101 fViewport = viewport;
108 void TGLCamera::UpdateCache()
const
112 glGetDoublev(GL_PROJECTION_MATRIX, fProjM.Arr());
113 glGetDoublev(GL_MODELVIEW_MATRIX, fModVM.Arr());
121 fFrustumPlanes[kRight].Set(fClipM[ 3] - fClipM[ 0],
122 fClipM[ 7] - fClipM[ 4],
123 fClipM[11] - fClipM[ 8],
124 fClipM[15] - fClipM[12]);
127 fFrustumPlanes[kLeft].Set(fClipM[ 3] + fClipM[ 0],
128 fClipM[ 7] + fClipM[ 4],
129 fClipM[11] + fClipM[ 8],
130 fClipM[15] + fClipM[12]);
133 fFrustumPlanes[kBottom].Set(fClipM[ 3] + fClipM[ 1],
134 fClipM[ 7] + fClipM[ 5],
135 fClipM[11] + fClipM[ 9],
136 fClipM[15] + fClipM[13]);
140 fFrustumPlanes[kTop].Set(fClipM[ 3] - fClipM[ 1],
141 fClipM[ 7] - fClipM[ 5],
142 fClipM[11] - fClipM[ 9],
143 fClipM[15] - fClipM[13]);
146 fFrustumPlanes[kFar].Set(fClipM[ 3] - fClipM[ 2],
147 fClipM[ 7] - fClipM[ 6],
148 fClipM[11] - fClipM[10],
149 fClipM[15] - fClipM[14]);
152 fFrustumPlanes[kNear].Set(fClipM[ 3] + fClipM[ 2],
153 fClipM[ 7] + fClipM[ 6],
154 fClipM[11] + fClipM[10],
155 fClipM[15] + fClipM[14]);
157 fCacheDirty = kFALSE;
171 TGLBoundingBox TGLCamera::Frustum(Bool_t asBox)
const
176 Error(
"TGLCamera::FrustumBox()",
"cache dirty - must call Apply()");
180 TGLVertex3 vertex[8];
191 vertex[4] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kBottom], fFrustumPlanes[kLeft]).second;
192 vertex[5] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kBottom], fFrustumPlanes[kRight]).second;
193 vertex[6] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kTop], fFrustumPlanes[kRight]).second;
194 vertex[7] = Intersection(fFrustumPlanes[kFar], fFrustumPlanes[kTop], fFrustumPlanes[kLeft]).second;
199 vertex[0] = fFrustumPlanes[kNear].NearestOn(vertex[4]);
200 vertex[1] = fFrustumPlanes[kNear].NearestOn(vertex[5]);
201 vertex[2] = fFrustumPlanes[kNear].NearestOn(vertex[6]);
202 vertex[3] = fFrustumPlanes[kNear].NearestOn(vertex[7]);
206 vertex[0] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kBottom], fFrustumPlanes[kLeft]).second;
207 vertex[1] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kBottom], fFrustumPlanes[kRight]).second;
208 vertex[2] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kTop], fFrustumPlanes[kRight]).second;
209 vertex[3] = Intersection(fFrustumPlanes[kNear], fFrustumPlanes[kTop], fFrustumPlanes[kLeft]).second;
212 return TGLBoundingBox(vertex);
219 TGLVertex3 TGLCamera::EyePoint()
const
222 Error(
"TGLPerspectiveCamera::FrustumBox()",
"cache dirty - must call Apply()");
229 return Intersection(fFrustumPlanes[kRight], fFrustumPlanes[kLeft], fFrustumPlanes[kTop]).second;
236 TGLVector3 TGLCamera::EyeDirection()
const
239 Error(
"TGLCamera::FrustumBox()",
"cache dirty - must call Apply()");
242 return fFrustumPlanes[kNear].Norm();
251 TGLVertex3 TGLCamera::FrustumCenter()
const
254 Error(
"TGLCamera::FrustumCenter()",
"cache dirty - must call Apply()");
256 std::pair<Bool_t, TGLVertex3> nearBottomLeft = Intersection(fFrustumPlanes[kNear],
257 fFrustumPlanes[kBottom],
258 fFrustumPlanes[kLeft]);
259 std::pair<Bool_t, TGLVertex3> farTopRight = Intersection(fFrustumPlanes[kFar],
260 fFrustumPlanes[kTop],
261 fFrustumPlanes[kRight]);
263 if (!nearBottomLeft.first || !farTopRight.first) {
264 Error(
"TGLCamera::FrustumCenter()",
"frustum planes invalid");
265 return TGLVertex3(0.0, 0.0, 0.0);
267 return nearBottomLeft.second + (farTopRight.second - nearBottomLeft.second)/2.0;
275 Rgl::EOverlap TGLCamera::FrustumOverlap(
const TGLBoundingBox & box)
const
278 Error(
"TGLCamera::FrustumOverlap()",
"cache dirty - must call Apply()");
287 Int_t planesInside = 0;
288 for (Int_t planeIndex = 0; planeIndex < kPlanesPerFrustum; ++planeIndex)
290 Rgl::EOverlap planeOverlap = box.Overlap(fFrustumPlanes[planeIndex]);
300 if (planeOverlap == Rgl::kOutside) {
301 return Rgl::kOutside;
302 }
else if (planeOverlap == Rgl::kInside) {
307 if (planesInside == kPlanesPerFrustum) {
310 return Rgl::kPartial;
319 Rgl::EOverlap TGLCamera::ViewportOverlap(
const TGLBoundingBox & box)
const
321 return ViewportRect(box).Overlap(fViewport);
329 TGLRect TGLCamera::ViewportRect(
const TGLBoundingBox & box,
330 const TGLBoundingBox::EFace face)
const
332 return ViewportRect(box, &face);
351 TGLRect TGLCamera::ViewportRect(
const TGLBoundingBox & box,
352 const TGLBoundingBox::EFace * face)
const
355 Error(
"TGLCamera::ViewportSize()",
"cache dirty - must call Apply()");
363 Double_t winX, winY, winZ;
370 vertexCount = box.FaceVertices(*face).size();
372 vertexCount = box.NumVertices();
375 for (UInt_t i = 0; i < vertexCount; i++)
377 const TGLVertex3 & vertex = face ? box.Vertex(box.FaceVertices(*face).at(i)) :
380 gluProject(vertex.X(), vertex.Y(), vertex.Z(),
381 fModVM.CArr(), fProjM.CArr(), fViewport.CArr(),
382 &winX, &winY, &winZ);
385 screenRect.SetCorner(static_cast<Int_t>(winX),static_cast<Int_t>(winY));
387 screenRect.Expand(static_cast<Int_t>(winX), static_cast<Int_t>(winY));
403 TGLVertex3 TGLCamera::WorldToViewport(
const TGLVertex3 & worldVertex,
404 TGLMatrix* modviewMat)
const
407 Error(
"TGLCamera::WorldToViewport()",
"cache dirty - must call Apply()");
409 TGLVertex3 viewportVertex;
410 gluProject(worldVertex[0], worldVertex[1], worldVertex[2],
411 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
412 fProjM.CArr(), fViewport.CArr(),
413 &viewportVertex[0], &viewportVertex[1], &viewportVertex[2]);
414 return viewportVertex;
426 TGLVector3 TGLCamera::WorldDeltaToViewport(
const TGLVertex3 & worldRef,
427 const TGLVector3 & worldDelta)
const
430 Error(
"TGLCamera::WorldToViewport()",
"cache dirty - must call Apply()");
432 TGLVertex3 other = worldRef + worldDelta;
433 TGLVertex3 v1 = WorldToViewport(worldRef);
434 TGLVertex3 v2 = WorldToViewport(other);
442 TGLVertex3 TGLCamera::ViewportToWorld(
const TGLVertex3 & viewportVertex,
443 TGLMatrix* modviewMat)
const
457 Error(
"TGLCamera::ViewportToWorld()",
"cache dirty - must call Apply()");
459 TGLVertex3 worldVertex;
460 gluUnProject(viewportVertex[0], viewportVertex[1], viewportVertex[2],
461 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
462 fProjM.CArr(), fViewport.CArr(),
463 &worldVertex[0], &worldVertex[1], &worldVertex[2]);
477 TGLLine3 TGLCamera::ViewportToWorld(Double_t viewportX, Double_t viewportY)
const
480 Error(
"TGLCamera::Viewport2DToWorldLine()",
"cache dirty - must call Apply()");
483 TGLVertex3 nearClipWorld = ViewportToWorld(TGLVertex3(viewportX, viewportY, 0.0));
484 TGLVertex3 farClipWorld = ViewportToWorld(TGLVertex3(viewportX, viewportY, 1.0));
485 return TGLLine3(nearClipWorld, farClipWorld - nearClipWorld);
498 TGLLine3 TGLCamera::ViewportToWorld(
const TPoint & viewport)
const
500 return ViewportToWorld(viewport.GetX(), viewport.GetY());
517 std::pair<Bool_t, TGLVertex3> TGLCamera::ViewportPlaneIntersection(Double_t viewportX, Double_t viewportY,
518 const TGLPlane & worldPlane)
const
520 TGLLine3 worldLine = ViewportToWorld(viewportX, viewportY);
523 return Intersection(worldPlane, worldLine, kTRUE );
533 std::pair<Bool_t, TGLVertex3> TGLCamera::ViewportPlaneIntersection(
const TPoint & viewport,
534 const TGLPlane & worldPlane)
const
536 return ViewportPlaneIntersection(viewport.GetX(), viewport.GetY(), worldPlane);
546 TGLVector3 TGLCamera::ViewportDeltaToWorld(
const TGLVertex3 & worldRef, Double_t viewportXDelta,
547 Double_t viewportYDelta, TGLMatrix* modviewMat)
const
550 Error(
"TGLCamera::ViewportDeltaToWorld()",
"cache dirty - must call Apply()");
552 TGLVertex3 winVertex = WorldToViewport(worldRef, modviewMat);
553 winVertex.Shift(viewportXDelta, viewportYDelta, 0.0);
554 return (ViewportToWorld(winVertex, modviewMat) - worldRef);
578 Bool_t TGLCamera::OfInterest(
const TGLBoundingBox & box, Bool_t ignoreSize)
const
580 Bool_t interest = kFALSE;
599 if (fInterestBox.IsEmpty())
601 if (box.Diagonal() >= fLargestSeen * 0.001)
603 if (box.Diagonal() > fLargestSeen) {
604 fLargestSeen = box.Diagonal();
621 if (ignoreSize || box.Diagonal() / fInterestBox.Diagonal() > 0.0001)
622 interest = fInterestBox.Overlap(box) != Rgl::kOutside;
643 Bool_t TGLCamera::UpdateInterest(Bool_t force)
645 Bool_t exposedUpdate = kFALSE;
648 TGLBoundingBox frustumBox = Frustum(kTRUE);
649 TGLBoundingBox newInterestBox(frustumBox);
654 TGLVector3 frustumExtents = frustumBox.Extents();
655 Double_t minBoxLength = frustumExtents.Mag() * fgInterestBoxExpansion;
656 newInterestBox.Scale(minBoxLength/frustumExtents[0], minBoxLength/frustumExtents[1], minBoxLength/frustumExtents[2]);
659 Double_t volRatio = 0.0;
663 if (!fInterestBox.IsEmpty()) {
664 volRatio = newInterestBox.Volume() / fInterestBox.Volume();
671 if (volRatio > 8.0 || volRatio < 0.125 || fInterestBox.IsEmpty() ||
672 fInterestBox.Overlap(frustumBox) != Rgl::kInside || force)
674 fPreviousInterestBox = fInterestBox;
675 fInterestBox = newInterestBox;
678 if (fInterestBox.Overlap(frustumBox) != Rgl::kInside) {
679 Error(
"TGLCamera::UpdateInterest",
"update interest box does not contain frustum");
682 exposedUpdate = kTRUE;
685 fInterestFrustum = Frustum(kFALSE);
686 fInterestFrustumAsBox = frustumBox;
688 if (gDebug>2 || force) {
689 Info(
"TGLCamera::UpdateInterest",
"changed - volume ratio %f", volRatio );
693 return exposedUpdate;
699 void TGLCamera::ResetInterest()
701 fInterestBox.SetEmpty();
722 Bool_t TGLCamera::AdjustAndClampVal(Double_t & val, Double_t min, Double_t max,
723 Int_t screenShift, Int_t screenShiftRange,
724 Bool_t mod1, Bool_t mod2)
const
726 if (screenShift == 0) {
731 Double_t sens = val *
static_cast<Double_t
>(screenShift);
744 Double_t oldVal = val;
745 Double_t shift = sens /
static_cast<Double_t
>(screenShiftRange);
751 else if (val > max) {
755 return val != oldVal;
762 Double_t TGLCamera::AdjustDelta(Double_t screenShift, Double_t deltaFactor,
763 Bool_t mod1, Bool_t mod2)
const
765 if (screenShift == 0)
782 return sens * deltaFactor * screenShift;
793 void TGLCamera::DrawDebugAids()
const
796 glColor3d(1.0,0.0,0.0);
797 fInterestFrustum.Draw();
800 glColor3d(1.0,0.65,0.15);
801 fInterestFrustumAsBox.Draw();
804 glColor3d(0.0,0.0,1.0);
809 fPreviousInterestBox.Draw();
813 TGLVertex3 start = EyePoint();
814 TGLVertex3 end = start + EyeDirection();
815 glColor3d(1.0,1.0,1.0);
817 glVertex3dv(start.CArr());
818 glVertex3dv(end.CArr());
825 void TGLCamera::SetExternalCenter(Bool_t enable)
827 if (fExternalCenter == enable)
830 fExternalCenter = enable;
832 fCenter = &fExtCenter;
834 fCenter = &fDefCenter;
836 TGLMatrix bt = fCamBase * fCamTrans;
837 fCamBase.SetBaseVec(4, *fCenter);
838 TGLMatrix binv = fCamBase; binv.Invert();
839 fCamTrans = binv * bt;
847 void TGLCamera::SetCenterVec(Double_t x, Double_t y, Double_t z)
850 fExtCenter.Set(x, y, z);
852 fDefCenter.Set(x, y, z);
854 TGLMatrix bt = fCamBase * fCamTrans;
855 fCamBase.SetBaseVec(4, *fCenter);
856 TGLMatrix binv = fCamBase; binv.Invert();
857 fCamTrans = binv * bt;
867 void TGLCamera::SetCenterVecWarp(Double_t x, Double_t y, Double_t z)
870 fExtCenter.Set(x, y, z);
872 fDefCenter.Set(x, y, z);
874 fCamBase.SetBaseVec(4, *fCenter);
882 Double_t TGLCamera::GetTheta()
const
884 TGLVector3 fwd = fCamTrans.GetBaseVec(1);
885 TGLVector3 zdir = fCamBase.GetBaseVec(3);
886 fCamBase.RotateIP(fwd);
887 return TMath::ACos(fwd*zdir);
894 Bool_t TGLCamera::Truck(Double_t xDelta, Double_t yDelta)
896 if (xDelta != 0 || yDelta != 0)
898 fCamTrans.MoveLF(2, xDelta);
899 fCamTrans.MoveLF(3, yDelta);
916 Bool_t TGLCamera::Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
918 Double_t vRotate = AdjustDelta(xDelta, TMath::TwoPi() / fViewport.Width(), mod1, mod2);
919 Double_t hRotate = AdjustDelta(yDelta, TMath::Pi() / fViewport.Height(), mod1, mod2);
921 return RotateRad(hRotate, vRotate);
927 Bool_t TGLCamera::RotateRad(Double_t hRotate, Double_t vRotate)
929 using namespace TMath;
933 Double_t *M = fCamTrans.Arr();
936 else if (d < -1) d = -1;
938 Double_t theta = ASin(d);
939 Double_t phi = Abs(Cos(theta)) > 8.7e-6 ? ATan2(M[1], M[0]) : ATan2(-M[4], M[5]);
941 M[0] = M[5] = M[10] = 1;
942 M[1] = M[2] = M[4] = M[6] = M[8] = M[9] = 0;
943 fCamTrans.RotateLF(1, 2, phi);
944 fCamTrans.RotateLF(1, 3, theta);
947 if (hRotate != 0.0 || fWasArcBalled)
949 TGLVector3 fwd = fCamTrans.GetBaseVec(1);
950 TGLVector3 lft = fCamTrans.GetBaseVec(2);
951 TGLVector3 up = fCamTrans.GetBaseVec(3);
952 TGLVector3 pos = fCamTrans.GetTranslation();
954 Double_t deltaF = pos * fwd;
955 Double_t deltaU = pos * up;
958 TGLVector3 zdir = fCamBase.GetBaseVec(3);
960 fCamBase.RotateIP(fwd);
961 Double_t theta = ACos(fwd*zdir);
962 if (theta + hRotate < fVAxisMinAngle)
963 hRotate = fVAxisMinAngle - theta;
964 else if (theta + hRotate > Pi() - fVAxisMinAngle)
965 hRotate = Pi() - fVAxisMinAngle - theta;
967 fCamTrans.MoveLF(1, -deltaF);
968 fCamTrans.MoveLF(3, -deltaU);
969 fCamTrans.RotateLF(3, 1, hRotate);
970 fCamTrans.MoveLF(3, deltaU);
971 fCamTrans.MoveLF(1, deltaF);
973 fWasArcBalled = kFALSE;
977 fCamTrans.RotatePF(1, 2, -vRotate);
990 Bool_t TGLCamera::RotateArcBall(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
992 Double_t vRotate = AdjustDelta(xDelta, TMath::TwoPi() / fViewport.Width(), mod1, mod2);
993 Double_t hRotate = AdjustDelta(yDelta, TMath::Pi() / fViewport.Height(), mod1, mod2);
995 return RotateArcBallRad(hRotate, vRotate);
1001 Bool_t TGLCamera::RotateArcBallRad(Double_t hRotate, Double_t vRotate)
1003 using namespace TMath;
1005 TGLVector3 fwd = fCamTrans.GetBaseVec(1);
1006 TGLVector3 lft = fCamTrans.GetBaseVec(2);
1007 TGLVector3 up = fCamTrans.GetBaseVec(3);
1008 TGLVector3 pos = fCamTrans.GetTranslation();
1010 Double_t deltaF = pos * fwd;
1011 Double_t deltaL = pos * lft;
1012 Double_t deltaU = pos * up;
1014 fCamTrans.MoveLF(1, -deltaF);
1015 fCamTrans.MoveLF(2, -deltaL);
1016 fCamTrans.MoveLF(3, -deltaU);
1020 fCamTrans.RotateLF(3, 1, hRotate);
1024 fCamTrans.RotateLF(1, 2, -vRotate);
1027 fCamTrans.MoveLF(3, deltaU);
1028 fCamTrans.MoveLF(2, deltaL);
1029 fCamTrans.MoveLF(1, deltaF);
1031 fWasArcBalled = kTRUE;
1046 Bool_t TGLCamera::Dolly(Int_t delta, Bool_t mod1, Bool_t mod2)
1048 Double_t step = AdjustDelta(delta, fDollyDistance, mod1, mod2);
1052 fCamTrans.MoveLF(1, -step);