Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGLCamera.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Richard Maunder 25/05/2005
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "TGLCamera.h"
13#include "TGLIncludes.h"
14#include "TGLBoundingBox.h"
15#include "TError.h"
16#include "TMath.h"
17
18/** \class TGLCamera
19\ingroup opengl
20Abstract base camera class - concrete classes for orthographic and
21perspective cameras derive from it. This class maintains values for
22the current:
23 1. Viewport
24 2. Projection, modelview and clip matrices - extracted from GL
25 3. The 6 frustum planes
26 4. Expanded frustum interest box
27
28It provides methods for various projection, overlap and intersection
29tests for viewport and world locations, against the true frustum and
30expanded interest box, and for extracting eye position and direction.
31
32It also defines the pure virtual manipulation interface methods the
33concrete ortho and perspective classes must implement.
34*/
35
36
39
40////////////////////////////////////////////////////////////////////////////////
41/// Default base camera constructor
42
44 fExternalCenter(kFALSE),
45 fFixDefCenter(kFALSE),
46 fWasArcBalled(kFALSE),
47 fCenter(&fDefCenter),
48 fNearClip(0), fFarClip(0),
49 fDollyDefault(1.0), fDollyDistance(1.0),
50 fVAxisMinAngle(0.01f),
51 fCacheDirty(kTRUE),
52 fTimeStamp (1),
53 fProjM(), fModVM(), fClipM(),
54 fViewport(0,0,100,100),
55 fLargestSeen(0.0)
56{
57 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
58 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
59 }
61 fCamBase.Set(origin, TGLVector3(1, 0, 0), TGLVector3(0, 0, 1));
62}
63
64////////////////////////////////////////////////////////////////////////////////
65/// Default base camera constructor
66
68 fExternalCenter(kFALSE),
69 fFixDefCenter(kFALSE),
70 fWasArcBalled(kFALSE),
71 fCenter(&fDefCenter),
72 fNearClip(0), fFarClip(0),
73 fDollyDefault(1.0), fDollyDistance(1.0),
74 fVAxisMinAngle(0.01f),
75 fCacheDirty(kTRUE),
76 fTimeStamp (1),
77 fProjM(), fModVM(), fClipM(),
78 fViewport(0,0,100,100),
79 fLargestSeen(0.0)
80{
81 for (UInt_t i = 0; i < kPlanesPerFrustum; i++ ) {
82 fFrustumPlanes[i].Set(1.0, 0.0, 0.0, 0.0);
83 }
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// Base camera destructor.
90
94
95////////////////////////////////////////////////////////////////////////////////
96/// Set viewport extents from passed 'viewport' rect.
97
103
104////////////////////////////////////////////////////////////////////////////////
105/// Update internally cached frustum values
106
108{
110
113
114 // Multiply projection by modelview to get the clip matrix
115 // TODO: Move this into TGLMatrix or shift all over to ROOT ones
116 fClipM = fProjM;
117 fClipM *= fModVM;
118
119 // RIGHT clipping plane
121 fClipM[ 7] - fClipM[ 4],
122 fClipM[11] - fClipM[ 8],
123 fClipM[15] - fClipM[12]);
124
125 // LEFT clipping plane
127 fClipM[ 7] + fClipM[ 4],
128 fClipM[11] + fClipM[ 8],
129 fClipM[15] + fClipM[12]);
130
131 // BOTTOM clipping plane
133 fClipM[ 7] + fClipM[ 5],
134 fClipM[11] + fClipM[ 9],
135 fClipM[15] + fClipM[13]);
136
138 // TOP clipping plane
140 fClipM[ 7] - fClipM[ 5],
141 fClipM[11] - fClipM[ 9],
142 fClipM[15] - fClipM[13]);
143
144 // FAR clipping plane
146 fClipM[ 7] - fClipM[ 6],
147 fClipM[11] - fClipM[10],
148 fClipM[15] - fClipM[14]);
149
150 // NEAR clipping plane
152 fClipM[ 7] + fClipM[ 6],
153 fClipM[11] + fClipM[10],
154 fClipM[15] + fClipM[14]);
155
157}
158
159////////////////////////////////////////////////////////////////////////////////
160/// Return the current camera frustum. If asBox == kFALSE return
161/// a true frustum (truncated square based pyramid). If asBox == kTRUE
162/// return a true box, using the far clipping plane intersection projected
163/// back to the near plane.
164///
165/// Camera must have valid frustum cache - call Apply() after last modification, before using
166///
167/// Note: TGLBoundingBox is not really valid when filled with truncated pyramid
168/// - this is used as a visual debug aid only so ok.
169
171{
172 // TODO: BoundingBox object is not always valid
173 // Need a generic bounding volume object
174 if (fCacheDirty) {
175 Error("TGLCamera::FrustumBox()", "cache dirty - must call Apply()");
176 }
177
178
180
181 // 7-------6
182 // /| /|
183 // 3-------2 |
184 // | 4-----|-5
185 // |/ |/
186 // 0-------1
187
188 // Get four vertices of frustum on the far clipping plane
189 // We assume they always intersect
194
195 if (asBox) {
196 // Now find the matching four vertices for above, projected onto near clip plane
197 // As near and far clip planes are parallel this forms a orientated box encompassing the frustum
202 } else {
203 // Returning true frustum - find vertices at near clipping plane
204 // We assume they always intersect
209 }
210
211 return TGLBoundingBox(vertex);
212}
213
214////////////////////////////////////////////////////////////////////////////////
215/// Return the camera eye point (vertex) in world space
216/// Camera must have valid frustum cache - call Apply() after last modification, before using
217
219{
220 if (fCacheDirty) {
221 Error("TGLPerspectiveCamera::FrustumBox()", "cache dirty - must call Apply()");
222 }
223
224 // Use intersection of right/left/top frustum planes - can be done in
225 // other ways from camera values but this is easiest.
226 // Note for an ortho camera this will result in an infinite z distance
227 // which is theoretically correct although of limited use
229}
230
231////////////////////////////////////////////////////////////////////////////////
232/// Extract the camera eye direction (vector), running from EyePoint()
233/// Camera must have valid frustum cache - call Apply() after last modification, before using
234
236{
237 if (fCacheDirty) {
238 Error("TGLCamera::FrustumBox()", "cache dirty - must call Apply()");
239 }
240 // Direction is just normal of near clipping plane
241 return fFrustumPlanes[kNear].Norm();
242}
243
244////////////////////////////////////////////////////////////////////////////////
245/// Find the center of the camera frustum from intersection of planes
246/// This method will work even with parallel left/right & top/bottom and
247/// infinite eye point of ortho cameras
248/// Camera must have valid frustum cache - call Apply() after last modification, before using
249
251{
252 if (fCacheDirty) {
253 Error("TGLCamera::FrustumCenter()", "cache dirty - must call Apply()");
254 }
255 std::pair<Bool_t, TGLVertex3> nearBottomLeft = Intersection(fFrustumPlanes[kNear],
258 std::pair<Bool_t, TGLVertex3> farTopRight = Intersection(fFrustumPlanes[kFar],
261 // Planes should intersect
262 if (!nearBottomLeft.first || !farTopRight.first) {
263 Error("TGLCamera::FrustumCenter()", "frustum planes invalid");
264 return TGLVertex3(0.0, 0.0, 0.0);
265 }
266 return nearBottomLeft.second + (farTopRight.second - nearBottomLeft.second)/2.0;
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Calculate overlap (kInside, kOutside, kPartial) of box with camera
271/// frustum
272/// Camera must have valid frustum cache - call Apply() after last modification, before using
273
275{
276 if (fCacheDirty) {
277 Error("TGLCamera::FrustumOverlap()", "cache dirty - must call Apply()");
278 }
279
280 // Test shape against each plane in frustum - returning overlap result
281 // This method can result in kFALSE positives, where shape lies outside
282 // frustum, but not outside a single plane of it. In this case the shape
283 // will be regarded incorrectly as intersecting (kPartial)
284 // TODO: Improve this - have a reliable test (separating axes).
285
286 Int_t planesInside = 0; // Assume outside to start
288 {
290
291 // Special case - any object which comes through the near clipping
292 // plane is completely removed - disabled at present
293 // TODO: In future may want to fade object (opacity) as they approach
294 // near clip - how will this be returned? template pair?
295 /*if (planeIndex == kNear && planeOverlap == kPartial) {
296 return kOutside;
297 }*/
298 // Once we find a single plane which shape is outside, we are outside the frustum
300 return Rgl::kOutside;
301 } else if (planeOverlap == Rgl::kInside) {
302 planesInside++;
303 }
304 }
305 // Completely inside frustum
307 return Rgl::kInside;
308 } else {
309 return Rgl::kPartial;
310 }
311}
312
313////////////////////////////////////////////////////////////////////////////////
314/// Calculate overlap (kInside, kOutside, kPartial) of box projection onto viewport
315/// (as rect) against the viewport rect.
316/// Camera must have valid frustum cache - call Apply() after last modification, before using.
317
322
323////////////////////////////////////////////////////////////////////////////////
324/// Calculate viewport rectangle which just contains projection of single 'face'
325/// of world frame bounding box 'box' onto the viewport. Note use other version
326/// of ViewportRect() if you want whole 'box' contained
327
333
334////////////////////////////////////////////////////////////////////////////////
335/// Calculate viewport rectangle which just contains projection of
336/// world frame bounding box 'box' onto the viewport. If face is
337/// null the rect contains the whole bounding box (8 vertices/6
338/// faces). If face is non-null it indicates a box face, and the
339/// rect contains the single face (4 vertices). Note use other
340/// version of ViewportRect() if you wish to just pass a static
341/// EFace enum member (e.g. kFaceLowX)
342///
343/// Note:
344/// 1. Rectangle is NOT clipped by viewport limits - so can result
345/// in rect with corners outside viewport - negative etc
346/// 2. TGLRect provides int (pixel based) values - not subpixel accurate
347/// 3. Camera must have valid frustum cache - call Apply() after last
348/// modification, before calling
349
351 const TGLBoundingBox::EFace * face) const
352{
353 if (fCacheDirty) {
354 Error("TGLCamera::ViewportSize()", "cache dirty - must call Apply()");
355 }
356
357 // TODO: Maybe TGLRect should be converted to Double_t so subpixel accurate
358 // Would give better LOD calculations at small sizes
359
360 // May often result in a rect bigger then the viewport
361 // as gluProject does not clip.
364
365 // TGLBoundingBox::Vertices() & TGLBoundingBox::FaceVertices() return
366 // const & vectors so this *should* all be efficient...
368 if (face) {
369 vertexCount = box.FaceVertices(*face).size();
370 } else {
371 vertexCount = box.NumVertices();
372 }
373
374 for (UInt_t i = 0; i < vertexCount; i++)
375 {
376 const TGLVertex3 & vertex = face ? box.Vertex(box.FaceVertices(*face).at(i)) :
377 box.Vertex(i);
378
379 gluProject(vertex.X(), vertex.Y(), vertex.Z(),
381 &winX, &winY, &winZ);
382
383 if (i == 0) {
384 screenRect.SetCorner(static_cast<Int_t>(winX),static_cast<Int_t>(winY));
385 } else {
386 screenRect.Expand(static_cast<Int_t>(winX), static_cast<Int_t>(winY));
387 }
388 }
389
390 return screenRect;
391}
392
393////////////////////////////////////////////////////////////////////////////////
394/// Convert a 3D world vertex to '3D' viewport (screen) one. The X()/Y()
395/// components of the viewport vertex are the horizontal/vertical pixel
396/// positions. The Z() component is the viewport depth value - for a
397/// default depth range this is 0.0 (at near clip plane) to 1.0 (at far
398/// clip plane). See OpenGL gluProject & glDepth documentation
399///
400/// Camera must have valid frustum cache - call Apply() after last modification, before using
401
403 TGLMatrix* modviewMat) const
404{
405 if (fCacheDirty) {
406 Error("TGLCamera::WorldToViewport()", "cache dirty - must call Apply()");
407 }
410 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
413 return viewportVertex;
414}
415
416////////////////////////////////////////////////////////////////////////////////
417/// Convert a 3D vector worldDelta (shift) about vertex worldRef to a viewport
418/// (screen) '3D' vector. The X()/Y() components of the vector are the horizontal /
419/// vertical pixel deltas. The Z() component is the viewport depth delta - for a
420/// default depth range between 0.0 (at near clip plane) to 1.0 (at far clip plane)
421/// See OpenGL gluProject & glDepth documentation
422///
423/// Camera must have valid frustum cache - call Apply()
424
426 const TGLVector3 & worldDelta) const
427{
428 if (fCacheDirty) {
429 Error("TGLCamera::WorldToViewport()", "cache dirty - must call Apply()");
430 }
434 return v2 - v1;
435}
436
437////////////////////////////////////////////////////////////////////////////////
438/// Convert a '3D' viewport vertex to 3D world one. The X()/Y() components
439/// of viewportVertex are the horizontal/vertical pixel position.
440
442 TGLMatrix* modviewMat) const
443{
444 // The Z() component is the viewport depth value - for a default
445 // depth range this is 0.0 (at near clip plane) to 1.0 (at far clip
446 // plane). Without Z() the viewport position corresponds to a line
447 // in 3D world space - see:
448 // TGLLine3 TGLCamera::ViewportToWorld(Double_t viewportX, Double_t viewportY) const
449 //
450 // See also OpenGL gluUnProject & glDepth documentation.
451 //
452 // Camera must have valid frustum cache - call Apply() after last
453 // modification, before using.
454
455 if (fCacheDirty) {
456 Error("TGLCamera::ViewportToWorld()", "cache dirty - must call Apply()");
457 }
460 modviewMat ? modviewMat->CArr() : fModVM.CArr(),
462 &worldVertex[0], &worldVertex[1], &worldVertex[2]);
463 return worldVertex;
464}
465
466////////////////////////////////////////////////////////////////////////////////
467/// Convert a 2D viewport position to 3D world line - the projection of the
468/// viewport point into 3D space. Line runs from near to far camera clip planes
469/// (the minimum and maximum visible depth). See also
470/// TGLVertex3 TGLCamera::ViewportToWorld(const TGLVertex3 & viewportVertex) const
471/// for 3D viewport -> 3D world vertex conversions.
472/// See also OpenGL gluUnProject & glDepth documentation
473///
474/// Camera must have valid frustum cache - call Apply() after last modification, before using
475
477{
478 if (fCacheDirty) {
479 Error("TGLCamera::Viewport2DToWorldLine()", "cache dirty - must call Apply()");
480 }
481 // Find world vertices at near and far clip planes, and return line through them
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// Convert a 2D viewport position to 3D world line - the projection of the
489/// viewport point into 3D space. Line runs from near to far camera clip planes
490/// (the minimum and maximum visible depth). See also
491/// TGLVertex3 TGLCamera::ViewportToWorld(const TGLVertex3 & viewportVertex) const
492/// for 3D viewport -> 3D world vertex conversions.
493/// See also OpenGL gluUnProject & glDepth documentation
494///
495/// Camera must have valid frustum cache - call Apply() after last modification, before using
496
498{
499 return ViewportToWorld(viewport.GetX(), viewport.GetY());
500}
501
502////////////////////////////////////////////////////////////////////////////////
503/// Find the intersection of projection of supplied viewport point (a 3D world
504/// line - see ViewportToWorld) with supplied world plane. Returns std::pair
505/// of Bool_t and TGLVertex3. If line intersects std::pair.first (Bool_t) is
506/// kTRUE, and std::pair.second (TGLVertex) contains the intersection vertex.
507/// If line does not intersect (line and plane parallel) std::pair.first
508/// (Bool_t) if kFALSE, and std::pair.second (TGLVertex) is invalid.
509///
510/// NOTE: The projection lines is extended for the plane intersection test
511/// hence the intersection vertex can lie outside the near/far clip regions
512/// (not visible)
513///
514/// Camera must have valid frustum cache - call Apply() after last modification, before using
515
517 const TGLPlane & worldPlane) const
518{
520
521 // Find intersection of line with plane
522 return Intersection(worldPlane, worldLine, kTRUE /* extended */ );
523}
524
525////////////////////////////////////////////////////////////////////////////////
526/// Find the intersection of projection of supplied viewport TPoint (a 3D world
527/// line - see ViewportToWorld) with supplied world plane. Returns std::pair
528/// of bool and vertex. If line intersects
529///
530/// Camera must have valid frustum cache - call Apply() after last modification, before using
531
532std::pair<Bool_t, TGLVertex3> TGLCamera::ViewportPlaneIntersection(const TPoint & viewport,
533 const TGLPlane & worldPlane) const
534{
536}
537
538////////////////////////////////////////////////////////////////////////////////
539/// Apply a 2D viewport delta (shift) to the projection of worldRef onto viewport,
540/// returning the resultant world vector which equates to it. Useful for making
541/// 3D world objects track mouse moves.
542///
543/// Camera must have valid frustum cache - call Apply()
544
547{
548 if (fCacheDirty) {
549 Error("TGLCamera::ViewportDeltaToWorld()", "cache dirty - must call Apply()");
550 }
554}
555
556////////////////////////////////////////////////////////////////////////////////
557/// Calculate if the an object defined by world frame bounding box
558/// is 'of interest' to the camera. This is defined as box:
559///
560/// 1. intersecting completely or partially (kInside/kPartial) with
561/// cameras interest box (fInterestBox)
562/// 2. having significant length OR volume ratio compared to this
563/// interest box
564///
565/// If a box is 'of interest' returns kTRUE, kFALSE otherwise. See
566/// TGLCamera::UpdateInterest() for more details of camera interest
567/// box.
568///
569/// Note: Length/volume ratios NOT dependent on the projected size
570/// of box at current camera configuration as we do not want
571/// continual changes. This is used when (re) populating the scene
572/// with objects from external client.
573///
574/// TODO: Might be more logical to move this test out to client -
575/// and have accessor for fInterestBox instead?
576
578{
580
581 // *********** IMPORTANT - Bootstrapping the camera with empty scene
582 //
583 // Initially the camera can't be Setup() (limits etc) until the
584 // scene is populated and it has a valid bounding box to pass to
585 // the camera. However the scene can't be populated without
586 // knowing if objects sent are 'of interest' - which needs a camera
587 // interest box, made from a properly setup camera frustum - catch
588 // 22.
589 //
590 // To overcome this we track the largest box diagonal seen so far and
591 // regard anything over 0.001 of this as 'of interest'. This enables
592 // us to get a roughly populated scene with largest objects, setup
593 // the camera, and do first draw. We then do a
594 // TGLCamera::UpdateInterest() - which always return kTRUE, and
595 // thus fires an internal rebuild to fill scene properly and
596 // finally setup camera properly.
597
598 if (fInterestBox.IsEmpty())
599 {
600 if (box.Diagonal() >= fLargestSeen * 0.001)
601 {
602 if (box.Diagonal() > fLargestSeen) {
603 fLargestSeen = box.Diagonal();
604 }
605 interest = kTRUE;
606 }
607 }
608 else
609 {
610 // Objects are of interest if the have length ratio c.f. the
611 // current interest box, and they at least partially overlap it.
612 // Some objects have zero volume BBs - e.g. single points - skip
613 // the test for these as there is no way to threshold on 0.
614 if (box.IsEmpty())
615 {
616 interest = kTRUE;
617 }
618 else
619 {
620 if (ignoreSize || box.Diagonal() / fInterestBox.Diagonal() > 0.0001)
622 }
623 }
624
625 return interest;
626}
627
628////////////////////////////////////////////////////////////////////////////////
629/// Update the internal interest box (fInterestBox) of the camera.
630/// The interest box is an orientated bounding box, calculated as
631/// an expanded container round the frustum. It is used to test if
632/// if object bounding boxes are of interest (should be accepted
633/// into viewer scene) for a camera - see TGLCamera::OfInterest()
634///
635/// The interest box is updated if the frustum is no longer contained
636/// in the existing one, or a new one calculated on the current frustum
637/// differs significantly in volume (camera has been zoomed/dollyed
638/// sizable amount).
639///
640/// If the interest box is updated we return kTRUE - kFALSE otherwise.
641
643{
645
646 // Construct a new interest box using the current frustum box as a basis
649
650 // The Z(2) axis of frustum (near->far plane) can be quite shallow c.f. X(0)/Y(1)
651 // For interest box we want to expand to ensure it is at least size
652 // of smaller X/Y to avoid excessive interest box recalculations
656
657 // Calculate volume ratio of new to old
658 Double_t volRatio = 0.0;
659
660 // If the interest box is empty the interest is ALWAYS updated
661 // See TGLCamera::OfInterest() comment on bootstrapping
662 if (!fInterestBox.IsEmpty()) {
664 }
665
666 // Update the existing interest box with new one if:
667 // 1. Volume ratio old/new interest has changed significantly
668 // 2. The current frustum is not inside existing interest
669 // 3. Force case (debugging)
670 if (volRatio > 8.0 || volRatio < 0.125 || fInterestBox.IsEmpty() ||
672 {
675
676 // Frustum should be fully contained now
678 Error("TGLCamera::UpdateInterest", "update interest box does not contain frustum");
679 }
680
682
683 // Keep the real frustum (true and box versions) as debugging aid
686
687 if (gDebug>2 || force) {
688 Info("TGLCamera::UpdateInterest", "changed - volume ratio %f", volRatio );
689 }
690 }
691
692 return exposedUpdate;
693}
694
695////////////////////////////////////////////////////////////////////////////////
696/// Clear out the existing interest box
697
699{
701
702 // We also reset the bootstrapping variable - see
703 // TGLCamera::OfInterest comments.
704 fLargestSeen = 0.0;
705}
706
707////////////////////////////////////////////////////////////////////////////////
708/// Adjust a passed REFERENCE value 'val', based on screenShift delta.
709/// Two modifier flags ('mod1' / 'mod2' ) for sensitivity:
710///
711/// - mod1 = kFALSE, mod2 = kFALSE : normal sensitivity (screenShift/screenShiftRange)
712/// - mod1 = kTRUE, mod2 = kFALSE : 0.1x sensitivity
713/// - mod1 = kTRUE, mod2 = kTRUE : 0.01x sensitivity
714/// - mod1 = kFALSE, mod2 = kTRUE : 10.0x sensitivity
715///
716/// 'val' is modified and clamped to 'min' / 'max' range.
717/// Return bool kTRUE if val actually changed.
718///
719/// Used as common interaction function for adjusting zoom/dolly etc
720
723 Bool_t mod1, Bool_t mod2) const
724{
725 if (screenShift == 0) {
726 return kFALSE;
727 }
728
729 // Calculate a sensitivity based on passed modifiers
730 Double_t sens = val * static_cast<Double_t>(screenShift);
731
732 if (mod1) {
733 sens *= 0.1;
734 if (mod2) {
735 sens *= 0.1;
736 }
737 } else {
738 if (mod2) {
739 sens *= 10.0;
740 }
741 }
742
743 Double_t oldVal = val;
744 Double_t shift = sens / static_cast<Double_t>(screenShiftRange);
745 val -= shift;
746
747 if (val < min) {
748 val = min;
749 }
750 else if (val > max) {
751 val = max;
752 }
753
754 return val != oldVal;
755}
756
757////////////////////////////////////////////////////////////////////////////////
758/// Adjust a passed screen value and apply modifiers.
759/// See AdjustAndClampVal() for details.
760
762 Bool_t mod1, Bool_t mod2) const
763{
764 if (screenShift == 0)
765 return 0;
766
767 // Calculate a sensitivity based on passed modifiers
768 Double_t sens = 1.0;
769
770 if (mod1) {
771 sens *= 0.1;
772 if (mod2) {
773 sens *= 0.1;
774 }
775 } else {
776 if (mod2) {
777 sens *= 10.0;
778 }
779 }
780
781 return sens * deltaFactor * screenShift;
782}
783
784////////////////////////////////////////////////////////////////////////////////
785/// Draw out some debugging aids for the camera:
786///
787/// 1. The frustum used to create the current interest box (RED)
788/// 2. The same frustum as a squared off box (ORANGE)
789/// 3. The axis aligned version of the frustum used as interest box basis (YELLOW)
790/// 4. The current interest box (BLUE)
791
793{
794 // Interest box frustum base (RED)
795 glColor3d(1.0,0.0,0.0);
797
798 // Interest box frustum as box (ORANGE)
799 glColor3d(1.0,0.65,0.15);
801
802 // Current Interest box (BLUE)
803 glColor3d(0.0,0.0,1.0);
805
806 // Previous interest (GREY)
807 glColor3d(.8,.7,.6);
809
810 // Also draw line from current eye point out in eye direction - should not
811 // appear if calculated correctly
812 TGLVertex3 start = EyePoint();
813 TGLVertex3 end = start + EyeDirection();
814 glColor3d(1.0,1.0,1.0);
815 glBegin(GL_LINES);
816 glVertex3dv(start.CArr());
817 glVertex3dv(end.CArr());
818 glEnd();
819}
820
821////////////////////////////////////////////////////////////////////////////////
822/// Set camera center diffrent than scene center, if enable is kTRUE.
823
825{
826 if (fExternalCenter == enable)
827 return;
828
830 if (fExternalCenter)
832 else
834
837 TGLMatrix binv = fCamBase; binv.Invert();
838 fCamTrans = binv * bt;
839
840 IncTimeStamp();
841}
842
843////////////////////////////////////////////////////////////////////////////////
844/// Set camera center vector.
845
847{
848 if (fExternalCenter)
849 fExtCenter.Set(x, y, z);
850 else
851 fDefCenter.Set(x, y, z);
852
855 TGLMatrix binv = fCamBase; binv.Invert();
856 fCamTrans = binv * bt;
857
858 IncTimeStamp();
859}
860
861////////////////////////////////////////////////////////////////////////////////
862/// Set camera center vector and do not keep the same combined
863/// camera transformation matrix.
864/// It appears as if the camera warped to the new center.
865
867{
868 if (fExternalCenter)
869 fExtCenter.Set(x, y, z);
870 else
871 fDefCenter.Set(x, y, z);
872
874
875 IncTimeStamp();
876}
877
878////////////////////////////////////////////////////////////////////////////////
879/// Get angle between camera up axis.
880
888
889////////////////////////////////////////////////////////////////////////////////
890/// Truck the camera - 'move camera parallel to film plane'.
891/// Returns kTRUE is redraw required (camera change), kFALSE otherwise.
892
894{
895 if (xDelta != 0 || yDelta != 0)
896 {
899
900 IncTimeStamp();
901 return kTRUE;
902 }
903 else
904 {
905 return kFALSE;
906 }
907}
908
909////////////////////////////////////////////////////////////////////////////////
910/// Rotate the camera round view volume center established in Setup().
911/// Arguments are:
912/// - xDelta - horizontal delta (pixels)
913/// - YDelta - vertical delta (pixels)
914
922
923////////////////////////////////////////////////////////////////////////////////
924/// Rotate camera around center.
925
927{
928 using namespace TMath;
929
930 if (fWasArcBalled)
931 {
932 Double_t *M = fCamTrans.Arr();
933 Double_t d = M[2];
934 if (d > 1) d = 1;
935 else if (d < -1) d = -1; // Fix numerical errors
936
937 Double_t theta = ASin(d);
938 Double_t phi = Abs(Cos(theta)) > 8.7e-6 ? ATan2(M[1], M[0]) : ATan2(-M[4], M[5]);
939
940 M[0] = M[5] = M[10] = 1;
941 M[1] = M[2] = M[4] = M[6] = M[8] = M[9] = 0;
942 fCamTrans.RotateLF(1, 2, phi);
943 fCamTrans.RotateLF(1, 3, theta);
944 }
945
946 if (hRotate != 0.0 || fWasArcBalled)
947 {
952
953 Double_t deltaF = pos * fwd;
954 Double_t deltaU = pos * up;
955
956 // up vector lock
958
960 Double_t theta = ACos(fwd*zdir);
961 if (theta + hRotate < fVAxisMinAngle)
962 hRotate = fVAxisMinAngle - theta;
963 else if (theta + hRotate > Pi() - fVAxisMinAngle)
964 hRotate = Pi() - fVAxisMinAngle - theta;
965
971
973 }
974 if (vRotate != 0.0)
975 {
976 fCamTrans.RotatePF(1, 2, -vRotate);
977 }
978
979 IncTimeStamp();
980 return kTRUE;
981}
982
983////////////////////////////////////////////////////////////////////////////////
984/// Rotate the camera round view volume center established in Setup().
985/// Arguments are:
986/// - xDelta - horizontal delta (pixels)
987/// - YDelta - vertical delta (pixels)
988
996
997////////////////////////////////////////////////////////////////////////////////
998/// Rotate camera around center.
999
1001{
1002 using namespace TMath;
1003
1008
1009 Double_t deltaF = pos * fwd;
1010 Double_t deltaL = pos * lft;
1011 Double_t deltaU = pos * up;
1012
1013 fCamTrans.MoveLF(1, -deltaF);
1014 fCamTrans.MoveLF(2, -deltaL);
1015 fCamTrans.MoveLF(3, -deltaU);
1016
1017 if (hRotate != 0.0)
1018 {
1019 fCamTrans.RotateLF(3, 1, hRotate);
1020 }
1021 if (vRotate != 0.0)
1022 {
1023 fCamTrans.RotateLF(1, 2, -vRotate);
1024 }
1025
1029
1031
1032 IncTimeStamp();
1033 return kTRUE;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Dolly the camera - 'move camera along eye line, retaining lens focal length'.
1038/// Arguments are:
1039///
1040/// - 'delta' - mouse viewport delta (pixels) - +ive dolly in, -ive dolly out
1041/// - 'mod1' / 'mod2' - sensitivity modifiers - see TGLCamera::AdjustAndClampVal()
1042///
1043/// Returns kTRUE is redraw required (camera change), kFALSE otherwise.
1044
1046{
1047 Double_t step = AdjustDelta(delta, fDollyDistance, mod1, mod2);
1048 if (step == 0)
1049 return kFALSE;
1050
1051 fCamTrans.MoveLF(1, -step);
1052
1053 IncTimeStamp();
1054 return kTRUE;
1055}
#define d(i)
Definition RSha256.hxx:102
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
std::pair< Bool_t, TGLLine3 > Intersection(const TGLPlane &p1, const TGLPlane &p2)
Find 3D line interestion of this plane with 'other'.
Definition TGLUtil.cxx:511
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
Concrete class describing an orientated (free) or axis aligned box of 8 vertices.
Double_t Volume() const
Double_t Diagonal() const
void SetEmpty()
Set bounding box empty - all vertices at (0,0,0)
Bool_t IsEmpty() const
Rgl::EOverlap Overlap(const TGLPlane &plane) const
Find overlap (Inside, Outside, Partial) of plane c.f. bounding box.
void Draw(Bool_t solid=kFALSE) const
Draw the bounding box as either wireframe (default) of solid using current GL color.
Rgl::EOverlap FrustumOverlap(const TGLBoundingBox &box) const
Calculate overlap (kInside, kOutside, kPartial) of box with camera frustum Camera must have valid fru...
static UInt_t fgDollyDeltaSens
Definition TGLCamera.h:112
TGLVector3 EyeDirection() const
Extract the camera eye direction (vector), running from EyePoint() Camera must have valid frustum cac...
virtual Bool_t RotateRad(Double_t hRotate, Double_t vRotate)
Rotate camera around center.
Bool_t fCacheDirty
Definition TGLCamera.h:95
TGLVertex3 FrustumCenter() const
Find the center of the camera frustum from intersection of planes This method will work even with par...
TGLCamera()
Default base camera constructor.
Definition TGLCamera.cxx:43
TGLVector3 fDefCenter
Definition TGLCamera.h:82
void ResetInterest()
Clear out the existing interest box.
virtual Bool_t Dolly(Int_t delta, Bool_t mod1, Bool_t mod2)
Dolly the camera - 'move camera along eye line, retaining lens focal length'.
TGLBoundingBox Frustum(Bool_t asBox=kTRUE) const
expansion c.f. aligned current frustum box
TGLMatrix fCamBase
Definition TGLCamera.h:76
virtual Bool_t RotateArcBallRad(Double_t hRotate, Double_t vRotate)
Rotate camera around center.
TGLVector3 * fCenter
Definition TGLCamera.h:84
void IncTimeStamp()
Definition TGLCamera.h:124
TGLMatrix fCamTrans
Definition TGLCamera.h:77
TGLMatrix fProjM
no-pick projection matrix (cached)
Definition TGLCamera.h:98
Bool_t AdjustAndClampVal(Double_t &val, Double_t min, Double_t max, Int_t screenShift, Int_t screenShiftRange, Bool_t mod1, Bool_t mod2) const
Adjust a passed REFERENCE value 'val', based on screenShift delta.
TGLVector3 ViewportDeltaToWorld(const TGLVertex3 &worldRef, Double_t viewportXDelta, Double_t viewportYDelta, TGLMatrix *modviewMat=nullptr) const
Apply a 2D viewport delta (shift) to the projection of worldRef onto viewport, returning the resultan...
virtual Bool_t Truck(Double_t xDelta, Double_t yDelta)
Truck the camera - 'move camera parallel to film plane'.
Rgl::EOverlap ViewportOverlap(const TGLBoundingBox &box) const
Calculate overlap (kInside, kOutside, kPartial) of box projection onto viewport (as rect) against the...
TGLBoundingBox fInterestBox
viewport (GL coords - origin bottom left)
Definition TGLCamera.h:105
TGLBoundingBox fInterestFrustumAsBox
frustum basis of current interest box - NOT a true BB! (DEBUG)
Definition TGLCamera.h:63
TGLRect ViewportRect(const TGLBoundingBox &box, TGLBoundingBox::EFace face) const
Calculate viewport rectangle which just contains projection of single 'face' of world frame bounding ...
virtual Bool_t Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
Rotate the camera round view volume center established in Setup().
void SetCenterVecWarp(Double_t x, Double_t y, Double_t z)
Set camera center vector and do not keep the same combined camera transformation matrix.
TGLVector3 fExtCenter
Definition TGLCamera.h:81
TGLRect fViewport
frustum planes (cached)
Definition TGLCamera.h:103
TGLVector3 WorldDeltaToViewport(const TGLVertex3 &worldRef, const TGLVector3 &worldDelta) const
Convert a 3D vector worldDelta (shift) about vertex worldRef to a viewport (screen) '3D' vector.
TGLMatrix fModVM
projection matrix (cached)
Definition TGLCamera.h:99
~TGLCamera() override
Base camera destructor.
Definition TGLCamera.cxx:91
TGLVertex3 WorldToViewport(const TGLVertex3 &worldVertex, TGLMatrix *modviewMat=nullptr) const
Convert a 3D world vertex to '3D' viewport (screen) one.
TGLPlane fFrustumPlanes[kPlanesPerFrustum]
object space clip matrix (cached)
Definition TGLCamera.h:101
Double_t GetTheta() const
Get angle between camera up axis.
Double_t fDollyDistance
Definition TGLCamera.h:91
std::pair< Bool_t, TGLVertex3 > ViewportPlaneIntersection(Double_t viewportX, Double_t viewportY, const TGLPlane &worldPlane) const
Find the intersection of projection of supplied viewport point (a 3D world line - see ViewportToWorld...
Bool_t UpdateInterest(Bool_t force)
Update the internal interest box (fInterestBox) of the camera.
void DrawDebugAids() const
Draw out some debugging aids for the camera:
TGLBoundingBox fInterestFrustum
previous interest box (DEBUG)
Definition TGLCamera.h:62
void UpdateCache() const
largest box diagonal seen in OfInterest() - used when bootstrapping interest box
Bool_t fExternalCenter
Definition TGLCamera.h:78
TGLMatrix fClipM
modelView matrix (cached)
Definition TGLCamera.h:100
@ kPlanesPerFrustum
Definition TGLCamera.h:54
Float_t fVAxisMinAngle
Definition TGLCamera.h:92
void SetExternalCenter(Bool_t x)
Set camera center diffrent than scene center, if enable is kTRUE.
void SetCenterVec(Double_t x, Double_t y, Double_t z)
Set camera center vector.
void SetViewport(const TGLRect &viewport)
Set viewport extents from passed 'viewport' rect.
Definition TGLCamera.cxx:98
TGLBoundingBox fPreviousInterestBox
Definition TGLCamera.h:61
Bool_t fWasArcBalled
Definition TGLCamera.h:80
virtual Bool_t RotateArcBall(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
Rotate the camera round view volume center established in Setup().
Double_t fLargestSeen
the interest box - created in UpdateInterest()
Definition TGLCamera.h:106
static const Double_t fgInterestBoxExpansion
frustum basis (as box) of current interest box (DEBUG)
Definition TGLCamera.h:65
Bool_t OfInterest(const TGLBoundingBox &box, Bool_t ignoreSize) const
Calculate if the an object defined by world frame bounding box is 'of interest' to the camera.
TGLVertex3 EyePoint() const
Return the camera eye point (vertex) in world space Camera must have valid frustum cache - call Apply...
Double_t AdjustDelta(Double_t screenShift, Double_t deltaFactor, Bool_t mod1, Bool_t mod2) const
Adjust a passed screen value and apply modifiers.
TGLVertex3 ViewportToWorld(const TGLVertex3 &viewportVertex, TGLMatrix *modviewMat=nullptr) const
Convert a '3D' viewport vertex to 3D world one.
3D space, fixed length, line class, with direction / length 'vector', passing through point 'vertex'.
Definition TGLUtil.h:387
16 component (4x4) transform matrix - column MAJOR as per GL.
Definition TGLUtil.h:598
void RotateLF(Int_t i1, Int_t i2, Double_t amount)
Rotate in local frame.
Definition TGLUtil.cxx:891
void MoveLF(Int_t ai, Double_t amount)
Translate in local frame.
Definition TGLUtil.cxx:807
Double_t * Arr()
Definition TGLUtil.h:665
void RotatePF(Int_t i1, Int_t i2, Double_t amount)
Rotate in parent frame. Does optimised version of MultLeft.
Definition TGLUtil.cxx:908
void SetBaseVec(Int_t b, Double_t x, Double_t y, Double_t z)
Definition TGLUtil.h:733
TGLVector3 GetBaseVec(Int_t b) const
Definition TGLUtil.h:754
const Double_t * CArr() const
Definition TGLUtil.h:664
TGLVector3 GetTranslation() const
Return the translation component of matrix.
Definition TGLUtil.cxx:788
void RotateIP(TGLVector3 &v) const
Rotate vector in-place. Translation is not applied.
Definition TGLUtil.cxx:1081
void Set(const TGLVertex3 &origin, const TGLVector3 &zAxis, const TGLVector3 &xAxis=nullptr)
Set matrix which when applied puts local origin at 'origin' and the local Z axis in direction 'z'.
Definition TGLUtil.cxx:730
3D plane class - of format Ax + By + Cz + D = 0
Definition TGLUtil.h:525
void Set(const TGLPlane &other)
Assign from other.
Definition TGLUtil.cxx:420
TGLVertex3 NearestOn(const TGLVertex3 &point) const
Return nearest point on plane.
Definition TGLUtil.cxx:495
TGLVector3 Norm() const
Definition TGLUtil.h:558
Viewport (pixel base) 2D rectangle class.
Definition TGLUtil.h:422
const Int_t * CArr() const
Definition TGLUtil.h:443
Int_t Height() const
Definition TGLUtil.h:452
Int_t Width() const
Definition TGLUtil.h:450
Rgl::EOverlap Overlap(const TGLRect &other) const
Return overlap result (kInside, kOutside, kPartial) of this rect with 'other'.
Definition TGLUtil.cxx:293
3 component (x/y/z) vector class.
Definition TGLUtil.h:248
3 component (x/y/z) vertex class.
Definition TGLUtil.h:84
void Set(Double_t x, Double_t y, Double_t z)
Definition TGLUtil.h:210
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
EOverlap
Definition TGLUtil.h:35
@ kInside
Definition TGLUtil.h:36
@ kOutside
Definition TGLUtil.h:38
@ kPartial
Definition TGLUtil.h:37
TMath.
Definition TMathBase.h:35
Double_t ACos(Double_t)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:643
constexpr Double_t Pi()
Definition TMath.h:40
constexpr Double_t TwoPi()
Definition TMath.h:47