```// @(#)root/gl:\$Id\$
// Author:  Richard Maunder  04/10/2005

/*************************************************************************
*                                                                       *
* For the licensing terms see \$ROOTSYS/LICENSE.                         *
* For the list of contributors see \$ROOTSYS/README/CREDITS.             *
*************************************************************************/

#include "TGLRotateManip.h"
#include "TGLPhysicalShape.h"
#include "TGLCamera.h"
#include "TGLIncludes.h"
#include "TMath.h"
#include "TError.h"

//______________________________________________________________________________
//
// Rotate manipulator - attaches to physical shape and draws local axes
// widgets - rings drawn from attached physical center, in plane defined
// by axis. User can mouse over (turns yellow) and L click/drag to
// rotate attached physical round the ring center.
// Widgets use standard 3D package axes colours: X red, Y green, Z blue.

ClassImp(TGLRotateManip);

//______________________________________________________________________________
Double_t TGLRotateManip::Angle(const TGLVector3& v1, const TGLVector3& v2)
{
// Calculate unsigned angle between vectors v1 and v2
return TMath::ACos(Dot(v1, v2) / (v1.Mag() * v2.Mag()));
}

//______________________________________________________________________________
Double_t TGLRotateManip::Angle(const TGLVector3& v1, const TGLVector3& v2,
const TGLVector3& ref)
{
// Calculate signed angle between vectors v1 and v2, using ref to define right handed coord system
// If v1.v2 parallel to ref vector: +ive for clockwise, -ive for anticlockwise
// If v1.v2 antiparallel to ref vector: -ive for clockwise, +ive for anticlockwise
TGLVector3 cross = Cross(v1, v2);
if (Dot(cross,ref) > 0.0) {
return Angle(v1, v2);
} else {
return -Angle(v1, v2);
}
}

//______________________________________________________________________________
TGLRotateManip::TGLRotateManip() :
fShallowRing(kFALSE), fShallowFront(kTRUE),
fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
{
// Construct rotation manipulator not bound to any physical shape.
}

//______________________________________________________________________________
TGLRotateManip::TGLRotateManip(TGLPhysicalShape* shape) :
TGLManip(shape),
fShallowRing(kFALSE), fShallowFront(kTRUE),
fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
{
// Construct rotation manipulator bound to TGLPhysicalShape 'shape'.
}

//______________________________________________________________________________
TGLRotateManip::~TGLRotateManip()
{
// Destory the rotation manipulator
}

//______________________________________________________________________________
void TGLRotateManip::Draw(const TGLCamera& camera) const
{
// Draw rotate manipulator - axis rings drawn from attached
// physical center, in plane defined by axis as normal, in red(X),
// green(Y) and blue(Z), with white center sphere. If selected
// widget (mouse over) this is drawn in active colour (yellow).

if (!fShape) {
return;
}

// Get draw scales
const TGLBoundingBox& box = fShape->BoundingBox();
Double_t baseScale;
TGLVector3 axisScale[3];
CalcDrawScale(box, camera, baseScale, axisScale);

// Get permitted manipulations on shape
TGLPhysicalShape::EManip manip = fShape->GetManip();

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);

TGLUtil::TDrawQualityScaler hiRes(3);

// Draw three axis rings where permitted
// Not drawing will prevent interaction
// GL name loading for hit testing - 0 reserved for no selection
if (manip & TGLPhysicalShape::kRotateX) {
glPushName(1);
glPopName();
} else {
}
if (manip & TGLPhysicalShape::kRotateY) {
glPushName(2);
glPopName();
} else {
}
if (manip & TGLPhysicalShape::kRotateZ) {
glPushName(3);
glPopName();
} else {
}
// Draw white center sphere

// Indicate we are in ring follow (non-shallow) mode
// by drawing line from center to dragged ring point
if (fActive) {
if (fShallowRing) {
TGLVertex3 eyeOnRing;
if (fShallowFront) {
} else {
}

eyeOnRing = fActiveRingPlane.NearestOn(eyeOnRing);
TGLVector3 arrowDir = Cross(fActiveRingPlane.Norm(), eyeOnRing - fActiveRingCenter);
arrowDir.Normalise();
} else {
TGLVector3 activeVector = fRingLine.Vector();
activeVector.Normalise();
TGLUtil::DrawLine(fRingLine.Start(), activeVector,
}
}

glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
}

//______________________________________________________________________________
Bool_t TGLRotateManip::HandleButton(const Event_t& event, const TGLCamera& camera)
{
// Handle mouse button event over manipulator - returns kTRUE if
// redraw required kFALSE otherwise.

Bool_t captured = TGLManip::HandleButton(event, camera);

if (captured) {
// Find active selected axis
UInt_t axisIndex = fSelectedWidget - 1; // Ugg sort out axis / widget id mapping
TGLVector3 widgetAxis = fShape->BoundingBox().Axis(axisIndex, kTRUE);

// Construct plane for the axis ring, using normal and center point
fActiveRingPlane.Set(widgetAxis, fShape->BoundingBox().Center());
fActiveRingCenter.Set(fShape->BoundingBox().Center());

fRingLineOld = fRingLine = CalculateRingLine(fLastMouse, camera);

// Is plane at shallow angle to eye line if angle between normal of plane and
// eye line is ~90 deg (PI/4)
Double_t planeEyeAngle = Angle(fActiveRingPlane.Norm(), camera.EyeDirection()) - TMath::ASin(1.0);
Double_t shallowDelta = 0.15;
if ((planeEyeAngle > -shallowDelta) && (planeEyeAngle < shallowDelta)) {
fShallowRing = kTRUE;

// Work out ring follow direction - if clicked on back or front of ring.
// If plane/eye angle very shallow force to front

/* DISABLED - Force onto front always */
fShallowFront = kTRUE;
/*
if ((planeEyeAngle > -shallowDelta/3.0) && (planeEyeAngle < shallowDelta/3.0) ||
Dot(fRingLine.Vector(), camera.FrustumPlane(TGLCamera::kNear).Norm()) < 0.0) {
fShallowFront = kTRUE;
} else {
fShallowFront = kFALSE;
}*/
} else {
fShallowRing = kFALSE;
}
}

return captured;
}

//______________________________________________________________________________
Bool_t TGLRotateManip::HandleMotion(const Event_t& event, const TGLCamera& camera)
{
// Handle mouse motion over manipulator - if active (selected
// widget) rotate physical around selected ring widget plane
// normal. Returns kTRUE if redraw required kFALSE otherwise.

if (fActive) {
TPoint newMouse(event.fX, event.fY);

// Calculate singed angle delta between old and new ring position using
Double_t angle = CalculateAngleDelta(newMouse, camera);
fShape->Rotate(fActiveRingCenter, fActiveRingPlane.Norm(), angle);
fLastMouse = newMouse;
return kTRUE;
}
return kFALSE;
}

//______________________________________________________________________________
Double_t TGLRotateManip::CalculateAngleDelta(const TPoint& mouse, const TGLCamera& camera)
{
// Calculate angle delta for rotation based on new mouse position.

if (fShallowRing) {
std::pair<Bool_t, TGLLine3> nearLineIntersection = Intersection(fActiveRingPlane,
camera.FrustumPlane(TGLCamera::kNear));
if (!nearLineIntersection.first) {
Error("TGLRotateManip::CalculateAngleDelta", "active ring plane parallel to near clip?");
return 1.0;
}
TGLLine3 nearLine = nearLineIntersection.second;
TGLVector3 activePlaneNear = camera.WorldDeltaToViewport(nearLine.Start(), nearLine.Vector());
activePlaneNear.Normalise();
TGLVector3 mouseDelta(mouse.GetX() - fLastMouse.GetX(),
-(mouse.GetY() - fLastMouse.GetY()),
0.0);

Double_t angle = Dot(activePlaneNear, mouseDelta) / 150.0;
if (fShallowFront) {
return -angle;
} else {
return angle;
}
} else {
fRingLineOld = fRingLine;
fRingLine = CalculateRingLine(fLastMouse, camera);
return Angle(fRingLineOld.Vector(), fRingLine.Vector(), fActiveRingPlane.Norm());
}
}

//______________________________________________________________________________
TGLLine3 TGLRotateManip::CalculateRingLine(const TPoint& mouse, const TGLCamera& camera) const
{
// Calculated interaction line between 'mouse' viewport point, and
// current selected widget (ring), under supplied 'camera'
// projection.

// Find mouse position in viewport coords
TPoint mouseViewport(mouse);
camera.WindowToViewport(mouseViewport);

// Find projection of mouse into world
TGLLine3 viewportProjection = camera.ViewportToWorld(mouseViewport);

// Find rotation line from ring center to this intersection on plane
std::pair<Bool_t, TGLVertex3> ringPlaneInter =  Intersection(fActiveRingPlane, viewportProjection, kTRUE);

// If intersection fails then ring is parallel to eye line - in this case
// force line to run from center back towards viewer (opposite eye line)
if (!ringPlaneInter.first) {
return TGLLine3(fActiveRingCenter, -camera.EyeDirection());
}
return TGLLine3(fActiveRingCenter, ringPlaneInter.second);
}

```
TGLRotateManip.cxx:1
TGLRotateManip.cxx:2
TGLRotateManip.cxx:3
TGLRotateManip.cxx:4
TGLRotateManip.cxx:5
TGLRotateManip.cxx:6
TGLRotateManip.cxx:7
TGLRotateManip.cxx:8
TGLRotateManip.cxx:9
TGLRotateManip.cxx:10
TGLRotateManip.cxx:11
TGLRotateManip.cxx:12
TGLRotateManip.cxx:13
TGLRotateManip.cxx:14
TGLRotateManip.cxx:15
TGLRotateManip.cxx:16
TGLRotateManip.cxx:17
TGLRotateManip.cxx:18
TGLRotateManip.cxx:19
TGLRotateManip.cxx:20
TGLRotateManip.cxx:21
TGLRotateManip.cxx:22
TGLRotateManip.cxx:23
TGLRotateManip.cxx:24
TGLRotateManip.cxx:25
TGLRotateManip.cxx:26
TGLRotateManip.cxx:27
TGLRotateManip.cxx:28
TGLRotateManip.cxx:29
TGLRotateManip.cxx:30
TGLRotateManip.cxx:31
TGLRotateManip.cxx:32
TGLRotateManip.cxx:33
TGLRotateManip.cxx:34
TGLRotateManip.cxx:35
TGLRotateManip.cxx:36
TGLRotateManip.cxx:37
TGLRotateManip.cxx:38
TGLRotateManip.cxx:39
TGLRotateManip.cxx:40
TGLRotateManip.cxx:41
TGLRotateManip.cxx:42
TGLRotateManip.cxx:43
TGLRotateManip.cxx:44
TGLRotateManip.cxx:45
TGLRotateManip.cxx:46
TGLRotateManip.cxx:47
TGLRotateManip.cxx:48
TGLRotateManip.cxx:49
TGLRotateManip.cxx:50
TGLRotateManip.cxx:51
TGLRotateManip.cxx:52
TGLRotateManip.cxx:53
TGLRotateManip.cxx:54
TGLRotateManip.cxx:55
TGLRotateManip.cxx:56
TGLRotateManip.cxx:57
TGLRotateManip.cxx:58
TGLRotateManip.cxx:59
TGLRotateManip.cxx:60
TGLRotateManip.cxx:61
TGLRotateManip.cxx:62
TGLRotateManip.cxx:63
TGLRotateManip.cxx:64
TGLRotateManip.cxx:65
TGLRotateManip.cxx:66
TGLRotateManip.cxx:67
TGLRotateManip.cxx:68
TGLRotateManip.cxx:69
TGLRotateManip.cxx:70
TGLRotateManip.cxx:71
TGLRotateManip.cxx:72
TGLRotateManip.cxx:73
TGLRotateManip.cxx:74
TGLRotateManip.cxx:75
TGLRotateManip.cxx:76
TGLRotateManip.cxx:77
TGLRotateManip.cxx:78
TGLRotateManip.cxx:79
TGLRotateManip.cxx:80
TGLRotateManip.cxx:81
TGLRotateManip.cxx:82
TGLRotateManip.cxx:83
TGLRotateManip.cxx:84
TGLRotateManip.cxx:85
TGLRotateManip.cxx:86
TGLRotateManip.cxx:87
TGLRotateManip.cxx:88
TGLRotateManip.cxx:89
TGLRotateManip.cxx:90
TGLRotateManip.cxx:91
TGLRotateManip.cxx:92
TGLRotateManip.cxx:93
TGLRotateManip.cxx:94
TGLRotateManip.cxx:95
TGLRotateManip.cxx:96
TGLRotateManip.cxx:97
TGLRotateManip.cxx:98
TGLRotateManip.cxx:99
TGLRotateManip.cxx:100
TGLRotateManip.cxx:101
TGLRotateManip.cxx:102
TGLRotateManip.cxx:103
TGLRotateManip.cxx:104
TGLRotateManip.cxx:105
TGLRotateManip.cxx:106
TGLRotateManip.cxx:107
TGLRotateManip.cxx:108
TGLRotateManip.cxx:109
TGLRotateManip.cxx:110
TGLRotateManip.cxx:111
TGLRotateManip.cxx:112
TGLRotateManip.cxx:113
TGLRotateManip.cxx:114
TGLRotateManip.cxx:115
TGLRotateManip.cxx:116
TGLRotateManip.cxx:117
TGLRotateManip.cxx:118
TGLRotateManip.cxx:119
TGLRotateManip.cxx:120
TGLRotateManip.cxx:121
TGLRotateManip.cxx:122
TGLRotateManip.cxx:123
TGLRotateManip.cxx:124
TGLRotateManip.cxx:125
TGLRotateManip.cxx:126
TGLRotateManip.cxx:127
TGLRotateManip.cxx:128
TGLRotateManip.cxx:129
TGLRotateManip.cxx:130
TGLRotateManip.cxx:131
TGLRotateManip.cxx:132
TGLRotateManip.cxx:133
TGLRotateManip.cxx:134
TGLRotateManip.cxx:135
TGLRotateManip.cxx:136
TGLRotateManip.cxx:137
TGLRotateManip.cxx:138
TGLRotateManip.cxx:139
TGLRotateManip.cxx:140
TGLRotateManip.cxx:141
TGLRotateManip.cxx:142
TGLRotateManip.cxx:143
TGLRotateManip.cxx:144
TGLRotateManip.cxx:145
TGLRotateManip.cxx:146
TGLRotateManip.cxx:147
TGLRotateManip.cxx:148
TGLRotateManip.cxx:149
TGLRotateManip.cxx:150
TGLRotateManip.cxx:151
TGLRotateManip.cxx:152
TGLRotateManip.cxx:153
TGLRotateManip.cxx:154
TGLRotateManip.cxx:155
TGLRotateManip.cxx:156
TGLRotateManip.cxx:157
TGLRotateManip.cxx:158
TGLRotateManip.cxx:159
TGLRotateManip.cxx:160
TGLRotateManip.cxx:161
TGLRotateManip.cxx:162
TGLRotateManip.cxx:163
TGLRotateManip.cxx:164
TGLRotateManip.cxx:165
TGLRotateManip.cxx:166
TGLRotateManip.cxx:167
TGLRotateManip.cxx:168
TGLRotateManip.cxx:169
TGLRotateManip.cxx:170
TGLRotateManip.cxx:171
TGLRotateManip.cxx:172
TGLRotateManip.cxx:173
TGLRotateManip.cxx:174
TGLRotateManip.cxx:175
TGLRotateManip.cxx:176
TGLRotateManip.cxx:177
TGLRotateManip.cxx:178
TGLRotateManip.cxx:179
TGLRotateManip.cxx:180
TGLRotateManip.cxx:181
TGLRotateManip.cxx:182
TGLRotateManip.cxx:183
TGLRotateManip.cxx:184
TGLRotateManip.cxx:185
TGLRotateManip.cxx:186
TGLRotateManip.cxx:187
TGLRotateManip.cxx:188
TGLRotateManip.cxx:189
TGLRotateManip.cxx:190
TGLRotateManip.cxx:191
TGLRotateManip.cxx:192
TGLRotateManip.cxx:193
TGLRotateManip.cxx:194
TGLRotateManip.cxx:195
TGLRotateManip.cxx:196
TGLRotateManip.cxx:197
TGLRotateManip.cxx:198
TGLRotateManip.cxx:199
TGLRotateManip.cxx:200
TGLRotateManip.cxx:201
TGLRotateManip.cxx:202
TGLRotateManip.cxx:203
TGLRotateManip.cxx:204
TGLRotateManip.cxx:205
TGLRotateManip.cxx:206
TGLRotateManip.cxx:207
TGLRotateManip.cxx:208
TGLRotateManip.cxx:209
TGLRotateManip.cxx:210
TGLRotateManip.cxx:211
TGLRotateManip.cxx:212
TGLRotateManip.cxx:213
TGLRotateManip.cxx:214
TGLRotateManip.cxx:215
TGLRotateManip.cxx:216
TGLRotateManip.cxx:217
TGLRotateManip.cxx:218
TGLRotateManip.cxx:219
TGLRotateManip.cxx:220
TGLRotateManip.cxx:221
TGLRotateManip.cxx:222
TGLRotateManip.cxx:223
TGLRotateManip.cxx:224
TGLRotateManip.cxx:225
TGLRotateManip.cxx:226
TGLRotateManip.cxx:227
TGLRotateManip.cxx:228
TGLRotateManip.cxx:229
TGLRotateManip.cxx:230
TGLRotateManip.cxx:231
TGLRotateManip.cxx:232
TGLRotateManip.cxx:233
TGLRotateManip.cxx:234
TGLRotateManip.cxx:235
TGLRotateManip.cxx:236
TGLRotateManip.cxx:237
TGLRotateManip.cxx:238
TGLRotateManip.cxx:239
TGLRotateManip.cxx:240
TGLRotateManip.cxx:241
TGLRotateManip.cxx:242
TGLRotateManip.cxx:243
TGLRotateManip.cxx:244
TGLRotateManip.cxx:245
TGLRotateManip.cxx:246
TGLRotateManip.cxx:247
TGLRotateManip.cxx:248
TGLRotateManip.cxx:249
TGLRotateManip.cxx:250
TGLRotateManip.cxx:251
TGLRotateManip.cxx:252
TGLRotateManip.cxx:253
TGLRotateManip.cxx:254
TGLRotateManip.cxx:255
TGLRotateManip.cxx:256
TGLRotateManip.cxx:257
TGLRotateManip.cxx:258
TGLRotateManip.cxx:259
TGLRotateManip.cxx:260
TGLRotateManip.cxx:261
TGLRotateManip.cxx:262
TGLRotateManip.cxx:263
TGLRotateManip.cxx:264
TGLRotateManip.cxx:265
TGLRotateManip.cxx:266
TGLRotateManip.cxx:267
TGLRotateManip.cxx:268
TGLRotateManip.cxx:269
TGLRotateManip.cxx:270
TGLRotateManip.cxx:271
TGLRotateManip.cxx:272
TGLRotateManip.cxx:273
TGLRotateManip.cxx:274
TGLRotateManip.cxx:275
TGLRotateManip.cxx:276
TGLRotateManip.cxx:277
TGLRotateManip.cxx:278
TGLRotateManip.cxx:279
TGLRotateManip.cxx:280
TGLRotateManip.cxx:281
TGLRotateManip.cxx:282
TGLRotateManip.cxx:283
TGLRotateManip.cxx:284
TGLRotateManip.cxx:285