Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
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
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
28
29////////////////////////////////////////////////////////////////////////////////
30/// Calculate unsigned angle between vectors v1 and v2
31
33{
34 return TMath::ACos(Dot(v1, v2) / (v1.Mag() * v2.Mag()));
35}
36
37////////////////////////////////////////////////////////////////////////////////
38/// Calculate signed angle between vectors v1 and v2, using ref to define right handed coord system
39/// - If v1.v2 parallel to ref vector: +ive for clockwise, -ive for anticlockwise
40/// - If v1.v2 antiparallel to ref vector: -ive for clockwise, +ive for anticlockwise
41
43 const TGLVector3& ref)
44{
45 TGLVector3 cross = Cross(v1, v2);
46 if (Dot(cross,ref) > 0.0) {
47 return Angle(v1, v2);
48 } else {
49 return -Angle(v1, v2);
50 }
51}
52
53////////////////////////////////////////////////////////////////////////////////
54/// Construct rotation manipulator not bound to any physical shape.
55
58 fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
59 fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
60 fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
61 fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
62{
63}
64
65////////////////////////////////////////////////////////////////////////////////
66/// Construct rotation manipulator bound to TGLPhysicalShape 'shape'.
67
69 TGLManip(shape),
71 fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
72 fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
73 fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
74 fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
75{
76}
77
78////////////////////////////////////////////////////////////////////////////////
79/// Destroy the rotation manipulator
80
84
85////////////////////////////////////////////////////////////////////////////////
86/// Draw rotate manipulator - axis rings drawn from attached
87/// physical center, in plane defined by axis as normal, in red(X),
88/// green(Y) and blue(Z), with white center sphere. If selected
89/// widget (mouse over) this is drawn in active colour (yellow).
90
91void TGLRotateManip::Draw(const TGLCamera& camera) const
92{
93 if (!fShape) {
94 return;
95 }
96
97 // Get draw scales
98 const TGLBoundingBox& box = fShape->BoundingBox();
99 Double_t baseScale;
100 TGLVector3 axisScale[3];
101 CalcDrawScale(box, camera, baseScale, axisScale);
102 Double_t ringRadius = baseScale*10.0;
103
104 // Get permitted manipulations on shape
105 TGLPhysicalShape::EManip manip = fShape->GetManip();
106
107 glEnable(GL_BLEND);
108 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109 glDisable(GL_CULL_FACE);
110
112
113 // Draw three axis rings where permitted
114 // Not drawing will prevent interaction
115 // GL name loading for hit testing - 0 reserved for no selection
116 if (manip & TGLPhysicalShape::kRotateX) {
117 glPushName(1);
118 TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, ColorFor(1));
119 glPopName();
120 } else {
121 TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, TGLUtil::fgGrey);
122 }
123 if (manip & TGLPhysicalShape::kRotateY) {
124 glPushName(2);
125 TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, ColorFor(2));
126 glPopName();
127 } else {
128 TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, TGLUtil::fgGrey);
129 }
130 if (manip & TGLPhysicalShape::kRotateZ) {
131 glPushName(3);
132 TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, ColorFor(3));
133 glPopName();
134 } else {
135 TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, TGLUtil::fgGrey);
136 }
137 // Draw white center sphere
138 TGLUtil::DrawSphere(box.Center(), ringRadius/20.0, TGLUtil::fgWhite);
139
140 // Indicate we are in ring follow (non-shallow) mode
141 // by drawing line from center to dragged ring point
142 if (fActive) {
143 if (fShallowRing) {
144 TGLVertex3 eyeOnRing;
145 if (fShallowFront) {
146 eyeOnRing = fActiveRingCenter - (camera.EyeDirection()*ringRadius);
147 } else {
148 eyeOnRing = fActiveRingCenter + (camera.EyeDirection()*ringRadius);
149 }
150
151 eyeOnRing = fActiveRingPlane.NearestOn(eyeOnRing);
152 TGLVector3 arrowDir = Cross(fActiveRingPlane.Norm(), eyeOnRing - fActiveRingCenter);
153 arrowDir.Normalise();
154 TGLUtil::DrawLine(eyeOnRing, arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
155 TGLUtil::DrawLine(eyeOnRing, -arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
156 } else {
157 TGLVector3 activeVector = fRingLine.Vector();
158 activeVector.Normalise();
159 activeVector *= ringRadius;
160 TGLUtil::DrawLine(fRingLine.Start(), activeVector,
162 }
163 }
164
165 glEnable(GL_CULL_FACE);
166 glDisable(GL_BLEND);
167}
168
169////////////////////////////////////////////////////////////////////////////////
170/// Handle mouse button event over manipulator - returns kTRUE if
171/// redraw required kFALSE otherwise.
172
174{
175 Bool_t captured = TGLManip::HandleButton(event, camera);
176
177 if (captured) {
178 // Find active selected axis
179 UInt_t axisIndex = fSelectedWidget - 1; // Ugg sort out axis / widget id mapping
180 TGLVector3 widgetAxis = fShape->BoundingBox().Axis(axisIndex, kTRUE);
181
182 // Construct plane for the axis ring, using normal and center point
183 fActiveRingPlane.Set(widgetAxis, fShape->BoundingBox().Center());
184 fActiveRingCenter.Set(fShape->BoundingBox().Center());
185
187
188 // Is plane at shallow angle to eye line if angle between normal of plane and
189 // eye line is ~90 deg (PI/4)
190 Double_t planeEyeAngle = Angle(fActiveRingPlane.Norm(), camera.EyeDirection()) - TMath::ASin(1.0);
191 Double_t shallowDelta = 0.15;
192 if ((planeEyeAngle > -shallowDelta) && (planeEyeAngle < shallowDelta)) {
194
195 // Work out ring follow direction - if clicked on back or front of ring.
196 // If plane/eye angle very shallow force to front
197
198 /* DISABLED - Force onto front always */
200 /*
201 if ((planeEyeAngle > -shallowDelta/3.0) && (planeEyeAngle < shallowDelta/3.0) ||
202 Dot(fRingLine.Vector(), camera.FrustumPlane(TGLCamera::kNear).Norm()) < 0.0) {
203 fShallowFront = kTRUE;
204 } else {
205 fShallowFront = kFALSE;
206 }*/
207 } else {
209 }
210 }
211
212 return captured;
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Handle mouse motion over manipulator - if active (selected
217/// widget) rotate physical around selected ring widget plane
218/// normal. Returns kTRUE if redraw required kFALSE otherwise.
219
221{
222 if (fActive) {
223 TPoint newMouse(event.fX, event.fY);
224
225 // Calculate singed angle delta between old and new ring position using
226 Double_t angle = CalculateAngleDelta(newMouse, camera);
227 fShape->Rotate(fActiveRingCenter, fActiveRingPlane.Norm(), angle);
228 fLastMouse = newMouse;
229 return kTRUE;
230 }
231 return kFALSE;
232}
233
234////////////////////////////////////////////////////////////////////////////////
235/// Calculate angle delta for rotation based on new mouse position.
236
238{
239 if (fShallowRing) {
240 std::pair<Bool_t, TGLLine3> nearLineIntersection = Intersection(fActiveRingPlane,
242 if (!nearLineIntersection.first) {
243 Error("TGLRotateManip::CalculateAngleDelta", "active ring plane parallel to near clip?");
244 return 1.0;
245 }
246 TGLLine3 nearLine = nearLineIntersection.second;
247 TGLVector3 activePlaneNear = camera.WorldDeltaToViewport(nearLine.Start(), nearLine.Vector());
248 activePlaneNear.Normalise();
249 TGLVector3 mouseDelta(mouse.GetX() - fLastMouse.GetX(),
250 -(mouse.GetY() - fLastMouse.GetY()),
251 0.0);
252
253 Double_t angle = Dot(activePlaneNear, mouseDelta) / 150.0;
254 if (fShallowFront) {
255 return -angle;
256 } else {
257 return angle;
258 }
259 } else {
262 return Angle(fRingLineOld.Vector(), fRingLine.Vector(), fActiveRingPlane.Norm());
263 }
264}
265
266////////////////////////////////////////////////////////////////////////////////
267/// Calculated interaction line between 'mouse' viewport point, and
268/// current selected widget (ring), under supplied 'camera'
269/// projection.
270
272{
273 // Find mouse position in viewport coords
274 TPoint mouseViewport(mouse);
275 camera.WindowToViewport(mouseViewport);
276
277 // Find projection of mouse into world
278 TGLLine3 viewportProjection = camera.ViewportToWorld(mouseViewport);
279
280 // Find rotation line from ring center to this intersection on plane
281 std::pair<Bool_t, TGLVertex3> ringPlaneInter = Intersection(fActiveRingPlane, viewportProjection, kTRUE);
282
283 // If intersection fails then ring is parallel to eye line - in this case
284 // force line to run from center back towards viewer (opposite eye line)
285 if (!ringPlaneInter.first) {
286 return TGLLine3(fActiveRingCenter, -camera.EyeDirection());
287 }
288 return TGLLine3(fActiveRingCenter, ringPlaneInter.second);
289}
290
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
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
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
Double_t Dot(const TGLVector3 &v1, const TGLVector3 &v2)
Definition TGLUtil.h:317
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
TGLVector3 Cross(const TGLVector3 &v1, const TGLVector3 &v2)
Definition TGLUtil.h:323
Concrete class describing an orientated (free) or axis aligned box of 8 vertices.
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...
TGLVector3 WorldDeltaToViewport(const TGLVertex3 &worldRef, const TGLVector3 &worldDelta) const
Convert a 3D vector worldDelta (shift) about vertex worldRef to a viewport (screen) '3D' vector.
void WindowToViewport(Int_t &, Int_t &y) const
Definition TGLCamera.h:198
const TGLPlane & FrustumPlane(EFrustumPlane plane) const
Definition TGLCamera.h:219
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
const TGLVector3 & Vector() const
Definition TGLUtil.h:406
const TGLVertex3 & Start() const
Definition TGLUtil.h:404
TPoint fLastMouse
! last (latest) 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:93
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:114
Bool_t fActive
! manipulator is active?
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:152
UInt_t fSelectedWidget
! active width (axis) component
Definition TGLManip.h:32
TGLPhysicalShape * fShape
! manipulated shape
Definition TGLManip.h:31
TGLManip(const TGLManip &)
Copy constructor.
Definition TGLManip.cxx:57
Concrete physical shape - a GL drawable.
Bool_t fShallowFront
! front or back of the active shallow ring?
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
! plane of the active ring (widget)
TGLLine3 fRingLineOld
void Draw(const TGLCamera &camera) const override
Draw rotate manipulator - axis rings drawn from attached physical center, in plane defined by axis as...
Bool_t HandleMotion(const Event_t &event, const TGLCamera &camera) override
Handle mouse motion over manipulator - if active (selected widget) rotate physical around selected ri...
TGLVertex3 fActiveRingCenter
! center of active ring
~TGLRotateManip() override
Destroy the rotation manipulator.
TGLRotateManip()
Construct rotation manipulator not bound to any physical shape.
Bool_t HandleButton(const Event_t &event, const TGLCamera &camera) override
Handle mouse button event over manipulator - returns kTRUE if redraw required kFALSE otherwise.
Bool_t fShallowRing
! does active ring form shallow angle to eye?
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])
Draw sphere, centered on vertex 'position', with radius 'radius', color 'rgba'.
Definition TGLUtil.cxx:2348
static const UChar_t fgWhite[4]
Definition TGLUtil.h:1425
@ kLineHeadNone
Definition TGLUtil.h:951
@ kLineHeadArrow
Definition TGLUtil.h:951
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:2363
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:2429
static const UChar_t fgGrey[4]
Definition TGLUtil.h:1426
static const UChar_t fgYellow[4]
Definition TGLUtil.h:1424
3 component (x/y/z) vector class.
Definition TGLUtil.h:248
void Normalise()
Definition TGLUtil.h:304
3 component (x/y/z) vertex class.
Definition TGLUtil.h:84
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)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:643
Double_t ASin(Double_t)
Returns the principal value of the arc sine of x, expressed in radians.
Definition TMath.h:635
Event structure.
Definition GuiTypes.h:175
Int_t fY
pointer x, y coordinates in event window
Definition GuiTypes.h:179
Int_t fX
Definition GuiTypes.h:179