Logo ROOT   6.10/09
Reference Guide
TGLRotateManip.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Richard Maunder 04/10/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, 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 "TGLRotateManip.h"
13 #include "TGLPhysicalShape.h"
14 #include "TGLCamera.h"
15 #include "TGLIncludes.h"
16 #include "TMath.h"
17 #include "TError.h"
18 
19 /** \class TGLRotateManip
20 \ingroup opengl
21 Rotate manipulator - attaches to physical shape and draws local axes
22 widgets - rings drawn from attached physical center, in plane defined
23 by axis. User can mouse over (turns yellow) and L click/drag to
24 rotate attached physical round the ring center.
25 Widgets use standard 3D package axes colours: X red, Y green, Z blue.
26 */
27 
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 /// Calculate unsigned angle between vectors v1 and v2
32 
34 {
35  return TMath::ACos(Dot(v1, v2) / (v1.Mag() * v2.Mag()));
36 }
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 /// Calculate signed angle between vectors v1 and v2, using ref to define right handed coord system
40 /// - If v1.v2 parallel to ref vector: +ive for clockwise, -ive for anticlockwise
41 /// - If v1.v2 antiparallel to ref vector: -ive for clockwise, +ive for anticlockwise
42 
44  const TGLVector3& ref)
45 {
46  TGLVector3 cross = Cross(v1, v2);
47  if (Dot(cross,ref) > 0.0) {
48  return Angle(v1, v2);
49  } else {
50  return -Angle(v1, v2);
51  }
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Construct rotation manipulator not bound to any physical shape.
56 
59  fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
60  fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
61  fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
62  fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
63 {
64 }
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// Construct rotation manipulator bound to TGLPhysicalShape 'shape'.
68 
70  TGLManip(shape),
72  fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
73  fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
74  fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
75  fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
76 {
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Destroy the rotation manipulator
81 
83 {
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Draw rotate manipulator - axis rings drawn from attached
88 /// physical center, in plane defined by axis as normal, in red(X),
89 /// green(Y) and blue(Z), with white center sphere. If selected
90 /// widget (mouse over) this is drawn in active colour (yellow).
91 
92 void TGLRotateManip::Draw(const TGLCamera& camera) const
93 {
94  if (!fShape) {
95  return;
96  }
97 
98  // Get draw scales
100  Double_t baseScale;
101  TGLVector3 axisScale[3];
102  CalcDrawScale(box, camera, baseScale, axisScale);
103  Double_t ringRadius = baseScale*10.0;
104 
105  // Get permitted manipulations on shape
107 
108  glEnable(GL_BLEND);
109  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
110  glDisable(GL_CULL_FACE);
111 
113 
114  // Draw three axis rings where permitted
115  // Not drawing will prevent interaction
116  // GL name loading for hit testing - 0 reserved for no selection
117  if (manip & TGLPhysicalShape::kRotateX) {
118  glPushName(1);
119  TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, ColorFor(1));
120  glPopName();
121  } else {
122  TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, TGLUtil::fgGrey);
123  }
124  if (manip & TGLPhysicalShape::kRotateY) {
125  glPushName(2);
126  TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, ColorFor(2));
127  glPopName();
128  } else {
129  TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, TGLUtil::fgGrey);
130  }
131  if (manip & TGLPhysicalShape::kRotateZ) {
132  glPushName(3);
133  TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, ColorFor(3));
134  glPopName();
135  } else {
136  TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, TGLUtil::fgGrey);
137  }
138  // Draw white center sphere
139  TGLUtil::DrawSphere(box.Center(), ringRadius/20.0, TGLUtil::fgWhite);
140 
141  // Indicate we are in ring follow (non-shallow) mode
142  // by drawing line from center to dragged ring point
143  if (fActive) {
144  if (fShallowRing) {
145  TGLVertex3 eyeOnRing;
146  if (fShallowFront) {
147  eyeOnRing = fActiveRingCenter - (camera.EyeDirection()*ringRadius);
148  } else {
149  eyeOnRing = fActiveRingCenter + (camera.EyeDirection()*ringRadius);
150  }
151 
152  eyeOnRing = fActiveRingPlane.NearestOn(eyeOnRing);
153  TGLVector3 arrowDir = Cross(fActiveRingPlane.Norm(), eyeOnRing - fActiveRingCenter);
154  arrowDir.Normalise();
155  TGLUtil::DrawLine(eyeOnRing, arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
156  TGLUtil::DrawLine(eyeOnRing, -arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
157  } else {
158  TGLVector3 activeVector = fRingLine.Vector();
159  activeVector.Normalise();
160  activeVector *= ringRadius;
161  TGLUtil::DrawLine(fRingLine.Start(), activeVector,
163  }
164  }
165 
166  glEnable(GL_CULL_FACE);
167  glDisable(GL_BLEND);
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 /// Handle mouse button event over manipulator - returns kTRUE if
172 /// redraw required kFALSE otherwise.
173 
175 {
176  Bool_t captured = TGLManip::HandleButton(event, camera);
177 
178  if (captured) {
179  // Find active selected axis
180  UInt_t axisIndex = fSelectedWidget - 1; // Ugg sort out axis / widget id mapping
181  TGLVector3 widgetAxis = fShape->BoundingBox().Axis(axisIndex, kTRUE);
182 
183  // Construct plane for the axis ring, using normal and center point
184  fActiveRingPlane.Set(widgetAxis, fShape->BoundingBox().Center());
186 
188 
189  // Is plane at shallow angle to eye line if angle between normal of plane and
190  // eye line is ~90 deg (PI/4)
191  Double_t planeEyeAngle = Angle(fActiveRingPlane.Norm(), camera.EyeDirection()) - TMath::ASin(1.0);
192  Double_t shallowDelta = 0.15;
193  if ((planeEyeAngle > -shallowDelta) && (planeEyeAngle < shallowDelta)) {
195 
196  // Work out ring follow direction - if clicked on back or front of ring.
197  // If plane/eye angle very shallow force to front
198 
199  /* DISABLED - Force onto front always */
201  /*
202  if ((planeEyeAngle > -shallowDelta/3.0) && (planeEyeAngle < shallowDelta/3.0) ||
203  Dot(fRingLine.Vector(), camera.FrustumPlane(TGLCamera::kNear).Norm()) < 0.0) {
204  fShallowFront = kTRUE;
205  } else {
206  fShallowFront = kFALSE;
207  }*/
208  } else {
210  }
211  }
212 
213  return captured;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Handle mouse motion over manipulator - if active (selected
218 /// widget) rotate physical around selected ring widget plane
219 /// normal. Returns kTRUE if redraw required kFALSE otherwise.
220 
222 {
223  if (fActive) {
224  TPoint newMouse(event.fX, event.fY);
225 
226  // Calculate singed angle delta between old and new ring position using
227  Double_t angle = CalculateAngleDelta(newMouse, camera);
229  fLastMouse = newMouse;
230  return kTRUE;
231  }
232  return kFALSE;
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Calculate angle delta for rotation based on new mouse position.
237 
239 {
240  if (fShallowRing) {
241  std::pair<Bool_t, TGLLine3> nearLineIntersection = Intersection(fActiveRingPlane,
243  if (!nearLineIntersection.first) {
244  Error("TGLRotateManip::CalculateAngleDelta", "active ring plane parallel to near clip?");
245  return 1.0;
246  }
247  TGLLine3 nearLine = nearLineIntersection.second;
248  TGLVector3 activePlaneNear = camera.WorldDeltaToViewport(nearLine.Start(), nearLine.Vector());
249  activePlaneNear.Normalise();
250  TGLVector3 mouseDelta(mouse.GetX() - fLastMouse.GetX(),
251  -(mouse.GetY() - fLastMouse.GetY()),
252  0.0);
253 
254  Double_t angle = Dot(activePlaneNear, mouseDelta) / 150.0;
255  if (fShallowFront) {
256  return -angle;
257  } else {
258  return angle;
259  }
260  } else {
264  }
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Calculated interaction line between 'mouse' viewport point, and
269 /// current selected widget (ring), under supplied 'camera'
270 /// projection.
271 
272 TGLLine3 TGLRotateManip::CalculateRingLine(const TPoint& mouse, const TGLCamera& camera) const
273 {
274  // Find mouse position in viewport coords
275  TPoint mouseViewport(mouse);
276  camera.WindowToViewport(mouseViewport);
277 
278  // Find projection of mouse into world
279  TGLLine3 viewportProjection = camera.ViewportToWorld(mouseViewport);
280 
281  // Find rotation line from ring center to this intersection on plane
282  std::pair<Bool_t, TGLVertex3> ringPlaneInter = Intersection(fActiveRingPlane, viewportProjection, kTRUE);
283 
284  // If intersection fails then ring is parallel to eye line - in this case
285  // force line to run from center back towards viewer (opposite eye line)
286  if (!ringPlaneInter.first) {
287  return TGLLine3(fActiveRingCenter, -camera.EyeDirection());
288  }
289  return TGLLine3(fActiveRingCenter, ringPlaneInter.second);
290 }
291 
static void DrawRing(const TGLVertex3 &center, const TGLVector3 &normal, Double_t radius, const UChar_t *rgba)
Draw ring, centered on &#39;center&#39;, lying on plane defined by &#39;center&#39; & &#39;normal&#39; of outer radius &#39;radiu...
Definition: TGLUtil.cxx:2399
TGLVertex3 fActiveRingCenter
plane of the active ring (widget)
Abstract base class for viewer manipulators, which allow direct in viewer manipulation of a (TGlPhysi...
Definition: TGLManip.h:28
TGLVertex3 Center() const
Abstract base camera class - concrete classes for orthographic and perspective cameras derive from it...
Definition: TGLCamera.h:43
static const UChar_t fgYellow[4]
Definition: TGLUtil.h:1050
virtual Bool_t HandleButton(const Event_t &event, const TGLCamera &camera)
Handle mouse button event over manipulator - returns kTRUE if redraw required kFALSE otherwise...
static void DrawLine(const TGLLine3 &line, ELineHeadShape head, Double_t size, const UChar_t rgba[4])
Draw thick line (tube) defined by &#39;line&#39;, with head at end shape &#39;head&#39; - box/arrow/none, (head) size &#39;size&#39;, color &#39;rgba&#39;.
Definition: TGLUtil.cxx:2333
TGLLine3 fRingLine
center of active ring
virtual void Draw(const TGLCamera &camera) const
Draw rotate manipulator - axis rings drawn from attached physical center, in plane defined by axis as...
Int_t fY
Definition: GuiTypes.h:177
virtual Bool_t HandleButton(const Event_t &event, const TGLCamera &camera)
Handle a mouse button event - return kTRUE if processed, kFALSE otherwise.
Definition: TGLManip.cxx:118
static const UChar_t fgGrey[4]
Definition: TGLUtil.h:1052
TGLVertex3 NearestOn(const TGLVertex3 &point) const
Return nearest point on plane.
Definition: TGLUtil.cxx:528
Bool_t fShallowFront
does active ring form shallow angle to eye?
bool Bool_t
Definition: RtypesCore.h:59
const TGLVertex3 & Start() const
Definition: TGLUtil.h:405
SCoord_t GetY() const
Definition: TPoint.h:48
SCoord_t GetX() const
Definition: TPoint.h:47
UInt_t fSelectedWidget
manipulated shape
Definition: TGLManip.h:32
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition: fillpatterns.C:1
void Set(Double_t x, Double_t y, Double_t z)
Definition: TGLUtil.h:209
TGLVertex3 ViewportToWorld(const TGLVertex3 &viewportVertex, TGLMatrix *modviewMat=0) const
Convert a &#39;3D&#39; viewport vertex to 3D world one.
Definition: TGLCamera.cxx:442
Concrete physical shape - a GL drawable.
EManip GetManip() const
TGLPlane fActiveRingPlane
front or back of the active shallow ring?
3 component (x/y/z) vertex class.
Definition: TGLUtil.h:82
void Rotate(const TGLVertex3 &pivot, const TGLVector3 &axis, Double_t angle)
static void DrawSphere(const TGLVertex3 &position, Double_t radius, const UChar_t rgba[4])
Draw sphere, centered on vertex &#39;position&#39;, with radius &#39;radius&#39;, color &#39;rgba&#39;.
Definition: TGLUtil.cxx:2318
const TGLBoundingBox & BoundingBox() const
TGLRotateManip()
Construct rotation manipulator not bound to any physical shape.
3 component (x/y/z) vector class.
Definition: TGLUtil.h:246
TPoint fLastMouse
first (start) mouse position (in WINDOW coords)
Definition: TGLManip.h:37
const UChar_t * ColorFor(UInt_t widget) const
Returns color to be used for given widget.
Definition: TGLManip.cxx:97
void Error(const char *location, const char *msgfmt,...)
Rotate manipulator - attaches to physical shape and draws local axes widgets - rings drawn from attac...
Definition: TPoint.h:31
Bool_t fActive
active width (axis) component
Definition: TGLManip.h:33
TGLLine3 fRingLineOld
Double_t Mag() const
Definition: TGLUtil.h:299
void WindowToViewport(Int_t &, Int_t &y) const
Definition: TGLCamera.h:198
static const UChar_t fgWhite[4]
Definition: TGLUtil.h:1051
TGLVector3 Norm() const
Definition: TGLUtil.h:557
TGLPhysicalShape * fShape
Definition: TGLManip.h:31
unsigned int UInt_t
Definition: RtypesCore.h:42
const TGLVector3 & Vector() const
Definition: TGLUtil.h:407
3D space, fixed length, line class, with direction / length &#39;vector&#39;, passing through point &#39;vertex&#39;...
Definition: TGLUtil.h:387
Double_t ACos(Double_t)
Definition: TMath.h:572
const Bool_t kFALSE
Definition: RtypesCore.h:92
Double_t Dot(const TGLVector3 &v1, const TGLVector3 &v2)
Definition: TGLUtil.h:318
#define ClassImp(name)
Definition: Rtypes.h:336
virtual Bool_t HandleMotion(const Event_t &event, const TGLCamera &camera)
Handle mouse motion over manipulator - if active (selected widget) rotate physical around selected ri...
double Double_t
Definition: RtypesCore.h:55
TGLVector3 WorldDeltaToViewport(const TGLVertex3 &worldRef, const TGLVector3 &worldDelta) const
Convert a 3D vector worldDelta (shift) about vertex worldRef to a viewport (screen) &#39;3D&#39; vector...
Definition: TGLCamera.cxx:426
Concrete class describing an orientated (free) or axis aligned box of 8 vertices. ...
void Normalise()
Definition: TGLUtil.h:305
Double_t CalculateAngleDelta(const TPoint &mouse, const TGLCamera &camera)
Calculate angle delta for rotation based on new mouse position.
const TGLPlane & FrustumPlane(EFrustumPlane plane) const
Definition: TGLCamera.h:219
void CalcDrawScale(const TGLBoundingBox &box, const TGLCamera &camera, Double_t &base, TGLVector3 axis[3]) const
Calculates base and axis scale factor (in world units) for drawing manipulators with reasonable size ...
Definition: TGLManip.cxx:156
Double_t ASin(Double_t)
Definition: TMath.h:566
const TGLVector3 & Axis(UInt_t i, Bool_t normalised=kTRUE) const
TGLVector3 Cross(const TGLVector3 &v1, const TGLVector3 &v2)
Definition: TGLUtil.h:324
static Double_t Angle(const TGLVector3 &v1, const TGLVector3 &v2)
Calculate unsigned angle between vectors v1 and v2.
const Bool_t kTRUE
Definition: RtypesCore.h:91
TGLLine3 CalculateRingLine(const TPoint &mouse, const TGLCamera &camera) const
Calculated interaction line between &#39;mouse&#39; viewport point, and current selected widget (ring)...
Int_t fX
Definition: GuiTypes.h:177
virtual ~TGLRotateManip()
Destroy the rotation manipulator.
void Set(const TGLPlane &other)
Assign from other.
Definition: TGLUtil.cxx:453
TGLVector3 EyeDirection() const
Extract the camera eye direction (vector), running from EyePoint() Camera must have valid frustum cac...
Definition: TGLCamera.cxx:236
std::pair< Bool_t, TGLLine3 > Intersection(const TGLPlane &p1, const TGLPlane &p2)
Find 3D line interestion of this plane with &#39;other&#39;.
Definition: TGLUtil.cxx:544