Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F101858663
quaternion_demo.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Feb 14, 11:19
Size
18 KB
Mime Type
text/x-c++
Expires
Sun, Feb 16, 11:19 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
24243356
Attached To
rDLMA Diffusion limited mixed aggregation
quaternion_demo.cpp
View Options
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "quaternion_demo.h"
#include "icosphere.h"
#include <Eigen/Geometry>
#include <Eigen/QR>
#include <Eigen/LU>
#include <iostream>
#include <QEvent>
#include <QMouseEvent>
#include <QInputDialog>
#include <QGridLayout>
#include <QButtonGroup>
#include <QRadioButton>
#include <QDockWidget>
#include <QPushButton>
#include <QGroupBox>
using
namespace
Eigen
;
class
FancySpheres
{
public
:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
FancySpheres
()
{
const
int
levels
=
4
;
const
float
scale
=
0.33
;
float
radius
=
100
;
std
::
vector
<
int
>
parents
;
// leval 0
mCenters
.
push_back
(
Vector3f
::
Zero
());
parents
.
push_back
(
-
1
);
mRadii
.
push_back
(
radius
);
// generate level 1 using icosphere vertices
radius
*=
0.45
;
{
float
dist
=
mRadii
[
0
]
*
0.9
;
for
(
int
i
=
0
;
i
<
12
;
++
i
)
{
mCenters
.
push_back
(
mIcoSphere
.
vertices
()[
i
]
*
dist
);
mRadii
.
push_back
(
radius
);
parents
.
push_back
(
0
);
}
}
static
const
float
angles
[
10
]
=
{
0
,
0
,
M_PI
,
0.
*
M_PI
,
M_PI
,
0.5
*
M_PI
,
M_PI
,
1.
*
M_PI
,
M_PI
,
1.5
*
M_PI
};
// generate other levels
int
start
=
1
;
for
(
int
l
=
1
;
l
<
levels
;
l
++
)
{
radius
*=
scale
;
int
end
=
mCenters
.
size
();
for
(
int
i
=
start
;
i
<
end
;
++
i
)
{
Vector3f
c
=
mCenters
[
i
];
Vector3f
ax0
=
(
c
-
mCenters
[
parents
[
i
]]).
normalized
();
Vector3f
ax1
=
ax0
.
unitOrthogonal
();
Quaternionf
q
;
q
.
setFromTwoVectors
(
Vector3f
::
UnitZ
(),
ax0
);
Affine3f
t
=
Translation3f
(
c
)
*
q
*
Scaling
(
mRadii
[
i
]
+
radius
);
for
(
int
j
=
0
;
j
<
5
;
++
j
)
{
Vector3f
newC
=
c
+
(
(
AngleAxisf
(
angles
[
j
*
2
+
1
],
ax0
)
*
AngleAxisf
(
angles
[
j
*
2
+
0
]
*
(
l
==
1
?
0.35
:
0.5
),
ax1
))
*
ax0
)
*
(
mRadii
[
i
]
+
radius
*
0.8
);
mCenters
.
push_back
(
newC
);
mRadii
.
push_back
(
radius
);
parents
.
push_back
(
i
);
}
}
start
=
end
;
}
}
void
draw
()
{
int
end
=
mCenters
.
size
();
glEnable
(
GL_NORMALIZE
);
for
(
int
i
=
0
;
i
<
end
;
++
i
)
{
Affine3f
t
=
Translation3f
(
mCenters
[
i
])
*
Scaling
(
mRadii
[
i
]);
gpu
.
pushMatrix
(
GL_MODELVIEW
);
gpu
.
multMatrix
(
t
.
matrix
(),
GL_MODELVIEW
);
mIcoSphere
.
draw
(
2
);
gpu
.
popMatrix
(
GL_MODELVIEW
);
}
glDisable
(
GL_NORMALIZE
);
}
protected
:
std
::
vector
<
Vector3f
>
mCenters
;
std
::
vector
<
float
>
mRadii
;
IcoSphere
mIcoSphere
;
};
// generic linear interpolation method
template
<
typename
T
>
T
lerp
(
float
t
,
const
T
&
a
,
const
T
&
b
)
{
return
a
*
(
1
-
t
)
+
b
*
t
;
}
// quaternion slerp
template
<>
Quaternionf
lerp
(
float
t
,
const
Quaternionf
&
a
,
const
Quaternionf
&
b
)
{
return
a
.
slerp
(
t
,
b
);
}
// linear interpolation of a frame using the type OrientationType
// to perform the interpolation of the orientations
template
<
typename
OrientationType
>
inline
static
Frame
lerpFrame
(
float
alpha
,
const
Frame
&
a
,
const
Frame
&
b
)
{
return
Frame
(
lerp
(
alpha
,
a
.
position
,
b
.
position
),
Quaternionf
(
lerp
(
alpha
,
OrientationType
(
a
.
orientation
),
OrientationType
(
b
.
orientation
))));
}
template
<
typename
_Scalar
>
class
EulerAngles
{
public
:
enum
{
Dim
=
3
};
typedef
_Scalar
Scalar
;
typedef
Matrix
<
Scalar
,
3
,
3
>
Matrix3
;
typedef
Matrix
<
Scalar
,
3
,
1
>
Vector3
;
typedef
Quaternion
<
Scalar
>
QuaternionType
;
protected
:
Vector3
m_angles
;
public
:
EulerAngles
()
{}
inline
EulerAngles
(
Scalar
a0
,
Scalar
a1
,
Scalar
a2
)
:
m_angles
(
a0
,
a1
,
a2
)
{}
inline
EulerAngles
(
const
QuaternionType
&
q
)
{
*
this
=
q
;
}
const
Vector3
&
coeffs
()
const
{
return
m_angles
;
}
Vector3
&
coeffs
()
{
return
m_angles
;
}
EulerAngles
&
operator
=
(
const
QuaternionType
&
q
)
{
Matrix3
m
=
q
.
toRotationMatrix
();
return
*
this
=
m
;
}
EulerAngles
&
operator
=
(
const
Matrix3
&
m
)
{
// mat = cy*cz -cy*sz sy
// cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
m_angles
.
coeffRef
(
1
)
=
std
::
asin
(
m
.
coeff
(
0
,
2
));
m_angles
.
coeffRef
(
0
)
=
std
::
atan2
(
-
m
.
coeff
(
1
,
2
),
m
.
coeff
(
2
,
2
));
m_angles
.
coeffRef
(
2
)
=
std
::
atan2
(
-
m
.
coeff
(
0
,
1
),
m
.
coeff
(
0
,
0
));
return
*
this
;
}
Matrix3
toRotationMatrix
(
void
)
const
{
Vector3
c
=
m_angles
.
array
().
cos
();
Vector3
s
=
m_angles
.
array
().
sin
();
Matrix3
res
;
res
<<
c
.
y
()
*
c
.
z
(),
-
c
.
y
()
*
s
.
z
(),
s
.
y
(),
c
.
z
()
*
s
.
x
()
*
s
.
y
()
+
c
.
x
()
*
s
.
z
(),
c
.
x
()
*
c
.
z
()
-
s
.
x
()
*
s
.
y
()
*
s
.
z
(),
-
c
.
y
()
*
s
.
x
(),
-
c
.
x
()
*
c
.
z
()
*
s
.
y
()
+
s
.
x
()
*
s
.
z
(),
c
.
z
()
*
s
.
x
()
+
c
.
x
()
*
s
.
y
()
*
s
.
z
(),
c
.
x
()
*
c
.
y
();
return
res
;
}
operator
QuaternionType
()
{
return
QuaternionType
(
toRotationMatrix
());
}
};
// Euler angles slerp
template
<>
EulerAngles
<
float
>
lerp
(
float
t
,
const
EulerAngles
<
float
>&
a
,
const
EulerAngles
<
float
>&
b
)
{
EulerAngles
<
float
>
res
;
res
.
coeffs
()
=
lerp
(
t
,
a
.
coeffs
(),
b
.
coeffs
());
return
res
;
}
RenderingWidget
::
RenderingWidget
()
{
mAnimate
=
false
;
mCurrentTrackingMode
=
TM_NO_TRACK
;
mNavMode
=
NavTurnAround
;
mLerpMode
=
LerpQuaternion
;
mRotationMode
=
RotationStable
;
mTrackball
.
setCamera
(
&
mCamera
);
// required to capture key press events
setFocusPolicy
(
Qt
::
ClickFocus
);
}
void
RenderingWidget
::
grabFrame
(
void
)
{
// ask user for a time
bool
ok
=
false
;
double
t
=
0
;
if
(
!
m_timeline
.
empty
())
t
=
(
--
m_timeline
.
end
())
->
first
+
1.
;
t
=
QInputDialog
::
getDouble
(
this
,
"Eigen's RenderingWidget"
,
"time value: "
,
t
,
0
,
1e3
,
1
,
&
ok
);
if
(
ok
)
{
Frame
aux
;
aux
.
orientation
=
mCamera
.
viewMatrix
().
linear
();
aux
.
position
=
mCamera
.
viewMatrix
().
translation
();
m_timeline
[
t
]
=
aux
;
}
}
void
RenderingWidget
::
drawScene
()
{
static
FancySpheres
sFancySpheres
;
float
length
=
50
;
gpu
.
drawVector
(
Vector3f
::
Zero
(),
length
*
Vector3f
::
UnitX
(),
Color
(
1
,
0
,
0
,
1
));
gpu
.
drawVector
(
Vector3f
::
Zero
(),
length
*
Vector3f
::
UnitY
(),
Color
(
0
,
1
,
0
,
1
));
gpu
.
drawVector
(
Vector3f
::
Zero
(),
length
*
Vector3f
::
UnitZ
(),
Color
(
0
,
0
,
1
,
1
));
// draw the fractal object
float
sqrt3
=
std
::
sqrt
(
3.
);
glLightfv
(
GL_LIGHT0
,
GL_AMBIENT
,
Vector4f
(
0.5
,
0.5
,
0.5
,
1
).
data
());
glLightfv
(
GL_LIGHT0
,
GL_DIFFUSE
,
Vector4f
(
0.5
,
1
,
0.5
,
1
).
data
());
glLightfv
(
GL_LIGHT0
,
GL_SPECULAR
,
Vector4f
(
1
,
1
,
1
,
1
).
data
());
glLightfv
(
GL_LIGHT0
,
GL_POSITION
,
Vector4f
(
-
sqrt3
,
-
sqrt3
,
sqrt3
,
0
).
data
());
glLightfv
(
GL_LIGHT1
,
GL_AMBIENT
,
Vector4f
(
0
,
0
,
0
,
1
).
data
());
glLightfv
(
GL_LIGHT1
,
GL_DIFFUSE
,
Vector4f
(
1
,
0.5
,
0.5
,
1
).
data
());
glLightfv
(
GL_LIGHT1
,
GL_SPECULAR
,
Vector4f
(
1
,
1
,
1
,
1
).
data
());
glLightfv
(
GL_LIGHT1
,
GL_POSITION
,
Vector4f
(
-
sqrt3
,
sqrt3
,
-
sqrt3
,
0
).
data
());
glMaterialfv
(
GL_FRONT_AND_BACK
,
GL_AMBIENT
,
Vector4f
(
0.7
,
0.7
,
0.7
,
1
).
data
());
glMaterialfv
(
GL_FRONT_AND_BACK
,
GL_DIFFUSE
,
Vector4f
(
0.8
,
0.75
,
0.6
,
1
).
data
());
glMaterialfv
(
GL_FRONT_AND_BACK
,
GL_SPECULAR
,
Vector4f
(
1
,
1
,
1
,
1
).
data
());
glMaterialf
(
GL_FRONT_AND_BACK
,
GL_SHININESS
,
64
);
glEnable
(
GL_LIGHTING
);
glEnable
(
GL_LIGHT0
);
glEnable
(
GL_LIGHT1
);
sFancySpheres
.
draw
();
glVertexPointer
(
3
,
GL_FLOAT
,
0
,
mVertices
[
0
].
data
());
glNormalPointer
(
GL_FLOAT
,
0
,
mNormals
[
0
].
data
());
glEnableClientState
(
GL_VERTEX_ARRAY
);
glEnableClientState
(
GL_NORMAL_ARRAY
);
glDrawArrays
(
GL_TRIANGLES
,
0
,
mVertices
.
size
());
glDisableClientState
(
GL_VERTEX_ARRAY
);
glDisableClientState
(
GL_NORMAL_ARRAY
);
glDisable
(
GL_LIGHTING
);
}
void
RenderingWidget
::
animate
()
{
m_alpha
+=
double
(
m_timer
.
interval
())
*
1e-3
;
TimeLine
::
const_iterator
hi
=
m_timeline
.
upper_bound
(
m_alpha
);
TimeLine
::
const_iterator
lo
=
hi
;
--
lo
;
Frame
currentFrame
;
if
(
hi
==
m_timeline
.
end
())
{
// end
currentFrame
=
lo
->
second
;
stopAnimation
();
}
else
if
(
hi
==
m_timeline
.
begin
())
{
// start
currentFrame
=
hi
->
second
;
}
else
{
float
s
=
(
m_alpha
-
lo
->
first
)
/
(
hi
->
first
-
lo
->
first
);
if
(
mLerpMode
==
LerpEulerAngles
)
currentFrame
=
::
lerpFrame
<
EulerAngles
<
float
>
>
(
s
,
lo
->
second
,
hi
->
second
);
else
if
(
mLerpMode
==
LerpQuaternion
)
currentFrame
=
::
lerpFrame
<
Eigen
::
Quaternionf
>
(
s
,
lo
->
second
,
hi
->
second
);
else
{
std
::
cerr
<<
"Invalid rotation interpolation mode (abort)
\n
"
;
exit
(
2
);
}
currentFrame
.
orientation
.
coeffs
().
normalize
();
}
currentFrame
.
orientation
=
currentFrame
.
orientation
.
inverse
();
currentFrame
.
position
=
-
(
currentFrame
.
orientation
*
currentFrame
.
position
);
mCamera
.
setFrame
(
currentFrame
);
updateGL
();
}
void
RenderingWidget
::
keyPressEvent
(
QKeyEvent
*
e
)
{
switch
(
e
->
key
())
{
case
Qt
::
Key_Up:
mCamera
.
zoom
(
2
);
break
;
case
Qt
::
Key_Down:
mCamera
.
zoom
(
-
2
);
break
;
// add a frame
case
Qt
::
Key_G:
grabFrame
();
break
;
// clear the time line
case
Qt
::
Key_C:
m_timeline
.
clear
();
break
;
// move the camera to initial pos
case
Qt
::
Key_R:
resetCamera
();
break
;
// start/stop the animation
case
Qt
::
Key_A:
if
(
mAnimate
)
{
stopAnimation
();
}
else
{
m_alpha
=
0
;
connect
(
&
m_timer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
animate
()));
m_timer
.
start
(
1000
/
30
);
mAnimate
=
true
;
}
break
;
default
:
break
;
}
updateGL
();
}
void
RenderingWidget
::
stopAnimation
()
{
disconnect
(
&
m_timer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
animate
()));
m_timer
.
stop
();
mAnimate
=
false
;
m_alpha
=
0
;
}
void
RenderingWidget
::
mousePressEvent
(
QMouseEvent
*
e
)
{
mMouseCoords
=
Vector2i
(
e
->
pos
().
x
(),
e
->
pos
().
y
());
bool
fly
=
(
mNavMode
==
NavFly
)
||
(
e
->
modifiers
()
&
Qt
::
ControlModifier
);
switch
(
e
->
button
())
{
case
Qt
::
LeftButton:
if
(
fly
)
{
mCurrentTrackingMode
=
TM_LOCAL_ROTATE
;
mTrackball
.
start
(
Trackball
::
Local
);
}
else
{
mCurrentTrackingMode
=
TM_ROTATE_AROUND
;
mTrackball
.
start
(
Trackball
::
Around
);
}
mTrackball
.
track
(
mMouseCoords
);
break
;
case
Qt
::
MidButton:
if
(
fly
)
mCurrentTrackingMode
=
TM_FLY_Z
;
else
mCurrentTrackingMode
=
TM_ZOOM
;
break
;
case
Qt
::
RightButton:
mCurrentTrackingMode
=
TM_FLY_PAN
;
break
;
default
:
break
;
}
}
void
RenderingWidget
::
mouseReleaseEvent
(
QMouseEvent
*
)
{
mCurrentTrackingMode
=
TM_NO_TRACK
;
updateGL
();
}
void
RenderingWidget
::
mouseMoveEvent
(
QMouseEvent
*
e
)
{
// tracking
if
(
mCurrentTrackingMode
!=
TM_NO_TRACK
)
{
float
dx
=
float
(
e
->
x
()
-
mMouseCoords
.
x
())
/
float
(
mCamera
.
vpWidth
());
float
dy
=
-
float
(
e
->
y
()
-
mMouseCoords
.
y
())
/
float
(
mCamera
.
vpHeight
());
// speedup the transformations
if
(
e
->
modifiers
()
&
Qt
::
ShiftModifier
)
{
dx
*=
10.
;
dy
*=
10.
;
}
switch
(
mCurrentTrackingMode
)
{
case
TM_ROTATE_AROUND:
case
TM_LOCAL_ROTATE:
if
(
mRotationMode
==
RotationStable
)
{
// use the stable trackball implementation mapping
// the 2D coordinates to 3D points on a sphere.
mTrackball
.
track
(
Vector2i
(
e
->
pos
().
x
(),
e
->
pos
().
y
()));
}
else
{
// standard approach mapping the x and y displacements as rotations
// around the camera's X and Y axes.
Quaternionf
q
=
AngleAxisf
(
dx
*
M_PI
,
Vector3f
::
UnitY
())
*
AngleAxisf
(
-
dy
*
M_PI
,
Vector3f
::
UnitX
());
if
(
mCurrentTrackingMode
==
TM_LOCAL_ROTATE
)
mCamera
.
localRotate
(
q
);
else
mCamera
.
rotateAroundTarget
(
q
);
}
break
;
case
TM_ZOOM
:
mCamera
.
zoom
(
dy
*
100
);
break
;
case
TM_FLY_Z
:
mCamera
.
localTranslate
(
Vector3f
(
0
,
0
,
-
dy
*
200
));
break
;
case
TM_FLY_PAN
:
mCamera
.
localTranslate
(
Vector3f
(
dx
*
200
,
dy
*
200
,
0
));
break
;
default
:
break
;
}
updateGL
();
}
mMouseCoords
=
Vector2i
(
e
->
pos
().
x
(),
e
->
pos
().
y
());
}
void
RenderingWidget
::
paintGL
()
{
glEnable
(
GL_DEPTH_TEST
);
glDisable
(
GL_CULL_FACE
);
glPolygonMode
(
GL_FRONT_AND_BACK
,
GL_FILL
);
glDisable
(
GL_COLOR_MATERIAL
);
glDisable
(
GL_BLEND
);
glDisable
(
GL_ALPHA_TEST
);
glDisable
(
GL_TEXTURE_1D
);
glDisable
(
GL_TEXTURE_2D
);
glDisable
(
GL_TEXTURE_3D
);
// Clear buffers
glClear
(
GL_COLOR_BUFFER_BIT
|
GL_DEPTH_BUFFER_BIT
);
mCamera
.
activateGL
();
drawScene
();
}
void
RenderingWidget
::
initializeGL
()
{
glClearColor
(
1.
,
1.
,
1.
,
0.
);
glLightModeli
(
GL_LIGHT_MODEL_LOCAL_VIEWER
,
1
);
glDepthMask
(
GL_TRUE
);
glColorMask
(
GL_TRUE
,
GL_TRUE
,
GL_TRUE
,
GL_TRUE
);
mCamera
.
setPosition
(
Vector3f
(
-
200
,
-
200
,
-
200
));
mCamera
.
setTarget
(
Vector3f
(
0
,
0
,
0
));
mInitFrame
.
orientation
=
mCamera
.
orientation
().
inverse
();
mInitFrame
.
position
=
mCamera
.
viewMatrix
().
translation
();
}
void
RenderingWidget
::
resizeGL
(
int
width
,
int
height
)
{
mCamera
.
setViewport
(
width
,
height
);
}
void
RenderingWidget
::
setNavMode
(
int
m
)
{
mNavMode
=
NavMode
(
m
);
}
void
RenderingWidget
::
setLerpMode
(
int
m
)
{
mLerpMode
=
LerpMode
(
m
);
}
void
RenderingWidget
::
setRotationMode
(
int
m
)
{
mRotationMode
=
RotationMode
(
m
);
}
void
RenderingWidget
::
resetCamera
()
{
if
(
mAnimate
)
stopAnimation
();
m_timeline
.
clear
();
Frame
aux0
=
mCamera
.
frame
();
aux0
.
orientation
=
aux0
.
orientation
.
inverse
();
aux0
.
position
=
mCamera
.
viewMatrix
().
translation
();
m_timeline
[
0
]
=
aux0
;
Vector3f
currentTarget
=
mCamera
.
target
();
mCamera
.
setTarget
(
Vector3f
::
Zero
());
// compute the rotation duration to move the camera to the target
Frame
aux1
=
mCamera
.
frame
();
aux1
.
orientation
=
aux1
.
orientation
.
inverse
();
aux1
.
position
=
mCamera
.
viewMatrix
().
translation
();
float
duration
=
aux0
.
orientation
.
angularDistance
(
aux1
.
orientation
)
*
0.9
;
if
(
duration
<
0.1
)
duration
=
0.1
;
// put the camera at that time step:
aux1
=
aux0
.
lerp
(
duration
/
2
,
mInitFrame
);
// and make it look at the target again
aux1
.
orientation
=
aux1
.
orientation
.
inverse
();
aux1
.
position
=
-
(
aux1
.
orientation
*
aux1
.
position
);
mCamera
.
setFrame
(
aux1
);
mCamera
.
setTarget
(
Vector3f
::
Zero
());
// add this camera keyframe
aux1
.
orientation
=
aux1
.
orientation
.
inverse
();
aux1
.
position
=
mCamera
.
viewMatrix
().
translation
();
m_timeline
[
duration
]
=
aux1
;
m_timeline
[
2
]
=
mInitFrame
;
m_alpha
=
0
;
animate
();
connect
(
&
m_timer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
animate
()));
m_timer
.
start
(
1000
/
30
);
mAnimate
=
true
;
}
QWidget
*
RenderingWidget
::
createNavigationControlWidget
()
{
QWidget
*
panel
=
new
QWidget
();
QVBoxLayout
*
layout
=
new
QVBoxLayout
();
{
QPushButton
*
but
=
new
QPushButton
(
"reset"
);
but
->
setToolTip
(
"move the camera to initial position (with animation)"
);
layout
->
addWidget
(
but
);
connect
(
but
,
SIGNAL
(
clicked
()),
this
,
SLOT
(
resetCamera
()));
}
{
// navigation mode
QGroupBox
*
box
=
new
QGroupBox
(
"navigation mode"
);
QVBoxLayout
*
boxLayout
=
new
QVBoxLayout
;
QButtonGroup
*
group
=
new
QButtonGroup
(
panel
);
QRadioButton
*
but
;
but
=
new
QRadioButton
(
"turn around"
);
but
->
setToolTip
(
"look around an object"
);
group
->
addButton
(
but
,
NavTurnAround
);
boxLayout
->
addWidget
(
but
);
but
=
new
QRadioButton
(
"fly"
);
but
->
setToolTip
(
"free navigation like a spaceship
\n
(this mode can also be enabled pressing the
\"
shift
\"
key)"
);
group
->
addButton
(
but
,
NavFly
);
boxLayout
->
addWidget
(
but
);
group
->
button
(
mNavMode
)
->
setChecked
(
true
);
connect
(
group
,
SIGNAL
(
buttonClicked
(
int
)),
this
,
SLOT
(
setNavMode
(
int
)));
box
->
setLayout
(
boxLayout
);
layout
->
addWidget
(
box
);
}
{
// track ball, rotation mode
QGroupBox
*
box
=
new
QGroupBox
(
"rotation mode"
);
QVBoxLayout
*
boxLayout
=
new
QVBoxLayout
;
QButtonGroup
*
group
=
new
QButtonGroup
(
panel
);
QRadioButton
*
but
;
but
=
new
QRadioButton
(
"stable trackball"
);
group
->
addButton
(
but
,
RotationStable
);
boxLayout
->
addWidget
(
but
);
but
->
setToolTip
(
"use the stable trackball implementation mapping
\n
the 2D coordinates to 3D points on a sphere"
);
but
=
new
QRadioButton
(
"standard rotation"
);
group
->
addButton
(
but
,
RotationStandard
);
boxLayout
->
addWidget
(
but
);
but
->
setToolTip
(
"standard approach mapping the x and y displacements
\n
as rotations around the camera's X and Y axes"
);
group
->
button
(
mRotationMode
)
->
setChecked
(
true
);
connect
(
group
,
SIGNAL
(
buttonClicked
(
int
)),
this
,
SLOT
(
setRotationMode
(
int
)));
box
->
setLayout
(
boxLayout
);
layout
->
addWidget
(
box
);
}
{
// interpolation mode
QGroupBox
*
box
=
new
QGroupBox
(
"spherical interpolation"
);
QVBoxLayout
*
boxLayout
=
new
QVBoxLayout
;
QButtonGroup
*
group
=
new
QButtonGroup
(
panel
);
QRadioButton
*
but
;
but
=
new
QRadioButton
(
"quaternion slerp"
);
group
->
addButton
(
but
,
LerpQuaternion
);
boxLayout
->
addWidget
(
but
);
but
->
setToolTip
(
"use quaternion spherical interpolation
\n
to interpolate orientations"
);
but
=
new
QRadioButton
(
"euler angles"
);
group
->
addButton
(
but
,
LerpEulerAngles
);
boxLayout
->
addWidget
(
but
);
but
->
setToolTip
(
"use Euler angles to interpolate orientations"
);
group
->
button
(
mNavMode
)
->
setChecked
(
true
);
connect
(
group
,
SIGNAL
(
buttonClicked
(
int
)),
this
,
SLOT
(
setLerpMode
(
int
)));
box
->
setLayout
(
boxLayout
);
layout
->
addWidget
(
box
);
}
layout
->
addItem
(
new
QSpacerItem
(
0
,
0
,
QSizePolicy
::
Minimum
,
QSizePolicy
::
Expanding
));
panel
->
setLayout
(
layout
);
return
panel
;
}
QuaternionDemo
::
QuaternionDemo
()
{
mRenderingWidget
=
new
RenderingWidget
();
setCentralWidget
(
mRenderingWidget
);
QDockWidget
*
panel
=
new
QDockWidget
(
"navigation"
,
this
);
panel
->
setAllowedAreas
((
QFlags
<
Qt
::
DockWidgetArea
>
)(
Qt
::
RightDockWidgetArea
|
Qt
::
LeftDockWidgetArea
));
addDockWidget
(
Qt
::
RightDockWidgetArea
,
panel
);
panel
->
setWidget
(
mRenderingWidget
->
createNavigationControlWidget
());
}
int
main
(
int
argc
,
char
*
argv
[])
{
std
::
cout
<<
"Navigation:
\n
"
;
std
::
cout
<<
" left button: rotate around the target
\n
"
;
std
::
cout
<<
" middle button: zoom
\n
"
;
std
::
cout
<<
" left button + ctrl quake rotate (rotate around camera position)
\n
"
;
std
::
cout
<<
" middle button + ctrl walk (progress along camera's z direction)
\n
"
;
std
::
cout
<<
" left button: pan (translate in the XY camera's plane)
\n\n
"
;
std
::
cout
<<
"R : move the camera to initial position
\n
"
;
std
::
cout
<<
"A : start/stop animation
\n
"
;
std
::
cout
<<
"C : clear the animation
\n
"
;
std
::
cout
<<
"G : add a key frame
\n
"
;
QApplication
app
(
argc
,
argv
);
QuaternionDemo
demo
;
demo
.
resize
(
600
,
500
);
demo
.
show
();
return
app
.
exec
();
}
#include "quaternion_demo.moc"
Event Timeline
Log In to Comment