ROOT   Reference Guide
TGLRotateManip.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Richard Maunder 04/10/2005
3
4/*************************************************************************
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
21Rotate manipulator - attaches to physical shape and draws local axes
22widgets - rings drawn from attached physical center, in plane defined
23by axis. User can mouse over (turns yellow) and L click/drag to
24rotate attached physical round the ring center.
25Widgets 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
58 fShallowRing(kFALSE), fShallowFront(kTRUE),
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),
71 fShallowRing(kFALSE), fShallowFront(kTRUE),
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
92void 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);
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
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();
157 } else {
158 TGLVector3 activeVector = fRingLine.Vector();
159 activeVector.Normalise();
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
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
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:365
void Error(const char *location, const char *msgfmt,...)
std::pair< Bool_t, TGLLine3 > Intersection(const TGLPlane &p1, const TGLPlane &p2)
Find 3D line interestion of this plane with 'other'.
Definition: TGLUtil.cxx:517
TGLVector3 Cross(const TGLVector3 &v1, const TGLVector3 &v2)
Definition: TGLUtil.h:322
Concrete class describing an orientated (free) or axis aligned box of 8 vertices.
TGLVertex3 Center() const
const TGLVector3 & Axis(UInt_t i, Bool_t normalised=kTRUE) const
Abstract base camera class - concrete classes for orthographic and perspective cameras derive from it...
Definition: TGLCamera.h:44
TGLVector3 EyeDirection() const
Extract the camera eye direction (vector), running from EyePoint() Camera must have valid frustum cac...
Definition: TGLCamera.cxx:236
TGLVertex3 ViewportToWorld(const TGLVertex3 &viewportVertex, TGLMatrix *modviewMat=0) const
Convert a '3D' viewport vertex to 3D world one.
Definition: TGLCamera.cxx:442
TGLVector3 WorldDeltaToViewport(const TGLVertex3 &worldRef, const TGLVector3 &worldDelta) const
Convert a 3D vector worldDelta (shift) about vertex worldRef to a viewport (screen) '3D' vector.
Definition: TGLCamera.cxx:426
void WindowToViewport(Int_t &, Int_t &y) const
Definition: TGLCamera.h:198
const TGLPlane & FrustumPlane(EFrustumPlane plane) const
Definition: TGLCamera.h:219
3D space, fixed length, line class, with direction / length 'vector', passing through point 'vertex'.
Definition: TGLUtil.h:386
const TGLVector3 & Vector() const
Definition: TGLUtil.h:405
const TGLVertex3 & Start() const
Definition: TGLUtil.h:403
Abstract base class for viewer manipulators, which allow direct in viewer manipulation of a (TGlPhysi...
Definition: TGLManip.h:29
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
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
Bool_t fActive
active width (axis) component
Definition: TGLManip.h:33
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
UInt_t fSelectedWidget
manipulated shape
Definition: TGLManip.h:32
TGLPhysicalShape * fShape
Definition: TGLManip.h:31
Concrete physical shape - a GL drawable.
const TGLBoundingBox & BoundingBox() const
void Rotate(const TGLVertex3 &pivot, const TGLVector3 &axis, Double_t angle)
EManip GetManip() const
void Set(const TGLPlane &other)
Assign from other.
Definition: TGLUtil.cxx:426
TGLVertex3 NearestOn(const TGLVertex3 &point) const
Return nearest point on plane.
Definition: TGLUtil.cxx:501
TGLVector3 Norm() const
Definition: TGLUtil.h:557
Rotate manipulator - attaches to physical shape and draws local axes widgets - rings drawn from attac...
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...
Bool_t fShallowFront
does active ring form shallow angle to eye?
TGLLine3 CalculateRingLine(const TPoint &mouse, const TGLCamera &camera) const
Calculated interaction line between 'mouse' viewport point, and current selected widget (ring),...
Double_t CalculateAngleDelta(const TPoint &mouse, const TGLCamera &camera)
Calculate angle delta for rotation based on new mouse position.
TGLPlane fActiveRingPlane
front or back of the active shallow ring?
virtual void Draw(const TGLCamera &camera) const
Draw rotate manipulator - axis rings drawn from attached physical center, in plane defined by axis as...
TGLLine3 fRingLineOld
TGLLine3 fRingLine
center of active ring
virtual Bool_t HandleButton(const Event_t &event, const TGLCamera &camera)
Handle mouse button event over manipulator - returns kTRUE if redraw required kFALSE otherwise.
TGLVertex3 fActiveRingCenter
plane of the active ring (widget)
TGLRotateManip()
Construct rotation manipulator not bound to any physical shape.
virtual ~TGLRotateManip()
Destroy the rotation manipulator.
static Double_t Angle(const TGLVector3 &v1, const TGLVector3 &v2)
Calculate unsigned angle between vectors v1 and v2.
static void DrawSphere(const TGLVertex3 &position, Double_t radius, const UChar_t rgba[4])
Definition: TGLUtil.cxx:2352
static const UChar_t fgWhite[4]
Definition: TGLUtil.h:1052
Definition: TGLUtil.h:947
Definition: TGLUtil.h:947
static void DrawLine(const TGLLine3 &line, ELineHeadShape head, Double_t size, const UChar_t rgba[4])
Draw thick line (tube) defined by 'line', with head at end shape 'head' - box/arrow/none,...
Definition: TGLUtil.cxx:2367
static void DrawRing(const TGLVertex3 &center, const TGLVector3 &normal, Double_t radius, const UChar_t *rgba)
Draw ring, centered on 'center', lying on plane defined by 'center' & 'normal' of outer radius 'radiu...
Definition: TGLUtil.cxx:2433
static const UChar_t fgGrey[4]
Definition: TGLUtil.h:1053
static const UChar_t fgYellow[4]
Definition: TGLUtil.h:1051
3 component (x/y/z) vector class.
Definition: TGLUtil.h:247
void Normalise()
Definition: TGLUtil.h:303
3 component (x/y/z) vertex class.
Definition: TGLUtil.h:83
void Set(Double_t x, Double_t y, Double_t z)
Definition: TGLUtil.h:209
Definition: TPoint.h:31
SCoord_t GetY() const
Definition: TPoint.h:47
SCoord_t GetX() const
Definition: TPoint.h:46
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition: fillpatterns.C:1
Double_t ACos(Double_t)
Definition: TMath.h:658
Double_t ASin(Double_t)
Definition: TMath.h:651
#define Dot(u, v)
Definition: normal.c:49
Int_t fY
Definition: GuiTypes.h:177
Int_t fX
Definition: GuiTypes.h:177