Signal/Geometry Processing Library (SPL) 1.1.24 |

Arcball.hpp
Go to the documentation of this file.
1 // Copyright (c) 2011 Michael D. Adams
2 // All rights reserved.
3
4 // __START_OF_LICENSE__
5 //
6 // Copyright (c) 2015 Michael D. Adams
7 // All rights reserved.
8 //
9 // This file is part of the Signal Processing Library (SPL).
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 3,
14 // or (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public
22 // License along with this program; see the file LICENSE. If not,
23 // see <http://www.gnu.org/licenses/>.
24 //
25 // __END_OF_LICENSE__
26
32 #ifndef SPL_Arcball_hpp
33 #define SPL_Arcball_hpp
34
36 // Header files
38
39 #include <SPL/config.hpp>
40 #include <CGAL/Plane_3.h>
41 #include <CGAL/Ray_3.h>
42 #include "cgalUtil.hpp"
43
45 //
47
48 namespace SPL {
49
55 // Geometry utility functions
58
63 template <class T>
64 typename T::Point_3 closestPointOnRay(const typename CGAL::Point_3<T>&
65 rayOrigin, const typename CGAL::Vector_3<T>& rayDir,
66 const typename CGAL::Point_3<T>& point)
67 {
68 typename T::FT t = (rayDir * (point - rayOrigin)) / (rayDir * rayDir);
69 if (t < 0) {
70 t = 0;
71 }
72 return typename T::Point_3(rayOrigin + t * rayDir);
73 }
74
89 template <class T>
90 std::pair<bool, typename T::Point_3> findRaySphereIntersection(
91 const typename CGAL::Point_3<T>& sphereCenter, typename T::FT sphereRadius,
92 const typename CGAL::Point_3<T>& rayOrigin,
93 const typename CGAL::Vector_3<T>& rayDir)
94 {
95 typename T::FT a = rayDir * rayDir;
96 typename T::Vector_3 delta = rayOrigin - sphereCenter;
97 typename T::FT b = 2.0 * delta * rayDir;
98 typename T::FT c = delta * delta - sphereRadius * sphereRadius;
99 typename T::FT discrim = b * b - 4.0 * a * c;
100 if (discrim < 0.0) {
101 return std::pair<bool, typename T::Point_3>(false,
102 closestPointOnRay(rayOrigin, rayDir, sphereCenter));
103 }
104 typename T::FT d = sqrt(discrim);
105 typename T::FT t0 = (-b - d) / (2.0 * a);
106 typename T::FT t1 = (-b + d) / (2.0 * a);
107 typename T::FT t = t0;
108 if (t1 >= 0 && t1 < t0) {
109 t = t1;
110 }
111 if (t < 0.0) {
112 return std::pair<bool, typename T::Point_3>(false,
113 closestPointOnRay(rayOrigin, rayDir, sphereCenter));
114 }
115 return std::pair<bool, typename T::Point_3>(true, rayOrigin + t * rayDir);
116 }
117
131 template <class T>
132 std::pair<bool, typename T::Point_3> findRayPlaneIntersection(
133 const typename CGAL::Point_3<T>& planePoint,
134 const typename CGAL::Vector_3<T>& planeNormal,
135 const typename CGAL::Point_3<T>& rayOrigin,
136 const typename CGAL::Vector_3<T>& rayDir)
137 {
138 typename T::Point_3 intersectPoint;
139 typename T::Ray_3 intersectRay;
140 CGAL::Object result = CGAL::intersection(typename T::Plane_3(planePoint,
141 planeNormal), typename T::Ray_3(rayOrigin, rayDir));
142 if (CGAL::assign(intersectPoint, result)) {
143 return std::pair<bool, typename T::Point_3>(true, intersectPoint);
144 } else if (CGAL::assign(intersectRay, result)) {
145 return std::pair<bool, typename T::Point_3>(true,
146 intersectRay.source());
147 } else {
148 return std::pair<bool, typename T::Point_3>(false, rayOrigin);
149 }
150 }
151
159 template <class T>
160 class Arcball
161 {
162 public:
163
165 typedef T Kernel;
166
168 typedef typename Kernel::Point_3 Point;
169
171 typedef typename Kernel::Vector_3 Vector;
172
174 typedef Rotation_3<Kernel> Rotation;
175
179 Arcball();
180
184 void initialize(double arcBallRadius, const Point& eyePos,
185 const Vector& eyeDir, const Vector& eyeUp, const Point& sceneCenter);
186
190 void setMode(int mode);
191
195 void start(const Point& pos);
196
200 void move(const Point& pos);
201
205 void clear();
206
211 Rotation getRotation() const;
212
216 static Rotation combineRotations(const Rotation&, const Rotation&);
217
221 void setDebugLevel(int debugLevel) const;
222
223 private:
224
225 // The arcball rotation mode.
226 int mode_;
227
228 // The arcball radius.
229 double arcBallRadius_;
230
231 // The eye position.
232 Point eyePos_;
233
234 // The eye up direction.
235 Vector eyeUp_;
236
237 // Indicates if the start position has been initialized.
238 bool startPosValid_;
239
240 // The start position for arcball movement.
241 Point startPos_;
242
243 // The current position for arcball movement.
244 Point curPos_;
245
246 // The scene center.
247 Point sceneCenter_;
248
249 // The level of debugging output.
250 int debugLevel_;
251
252 };
253
254 template <class T>
255 Arcball<T>::Arcball() : mode_(0), arcBallRadius_(1), eyePos_(0, 0, 0),
256 eyeUp_(0, 0, 0), startPosValid_(false), startPos_(0, 0, 0),
257 curPos_(0, 0, 0), sceneCenter_(0, 0, 0), debugLevel_(0)
258 {
259 }
260
261 template <class T>
262 void Arcball<T>::initialize(double arcBallRadius,
263 const typename T::Point_3& eyePos,
264 const typename T::Vector_3& eyeDir,
265 const typename T::Vector_3& eyeUp,
266 const typename T::Point_3& sceneCenter)
267 {
268 mode_ = 0;
269 arcBallRadius_ = arcBallRadius;
270 eyePos_ = eyePos;
271 sceneCenter_ = sceneCenter;
272 eyeUp_ = eyeUp;
273 clear();
274 }
275
276 template <class T>
277 void Arcball<T>::setMode(int mode)
278 {
279 mode_ = mode;
280 }
281
282 template <class T>
283 void Arcball<T>::start(const Arcball<T>::Point& pos)
284 {
285 startPos_ = pos;
286 curPos_ = pos;
287 startPosValid_ = true;
288 if (debugLevel_ > 0) {
289 std::cerr
290 << "start: startPos=" << startPos_ << " curPos=" << curPos_ << "\n";
291 }
292 }
293
294 template <class T>
295 void Arcball<T>::move(const Arcball<T>::Point& pos)
296 {
297 curPos_ = pos;
298 if (debugLevel_ > 0) {
299 std::cerr
300 << "move: startPos=" << startPos_ << " curPos=" << curPos_ << "\n";
301 }
302 }
303
304 template <class T>
305 void Arcball<T>::clear()
306 {
307 startPosValid_ = false;
308 startPos_ = typename T::Point_3(0, 0, 0);
309 curPos_ = startPos_;
310 if (debugLevel_ > 0) {
311 std::cerr
312 << "clear: startPos=" << startPos_ << " curPos=" << curPos_ << "\n";
313 }
314 }
315
316 template <class T>
317 typename Arcball<T>::Rotation Arcball<T>::getRotation() const
318 {
319 // Ensure that the starting position has been initialized by the user.
320 assert(startPosValid_);
321
322 if (debugLevel_ > 0) {
323 std::cerr << "startPos=" << startPos_ << " curPos=" << curPos_ << "\n";
324 }
325
326 // Calculate the required rotation based on the mouse movement.
327 std::pair<bool, typename T::Point_3> oldResult;
328 std::pair<bool, typename T::Point_3> curResult;
329 if (mode_ == 0) {
330 oldResult = findRaySphereIntersection<T>(sceneCenter_,
331 arcBallRadius_, eyePos_, startPos_ - eyePos_);
332 curResult = findRaySphereIntersection<T>(sceneCenter_,
333 arcBallRadius_, eyePos_, curPos_ - eyePos_);
334 if (!oldResult.first && !curResult.first) {
335 oldResult = findRayPlaneIntersection<T>(sceneCenter_,
336 eyePos_ - sceneCenter_, eyePos_, startPos_ - eyePos_);
337 curResult = findRayPlaneIntersection<T>(sceneCenter_,
338 eyePos_ - sceneCenter_, eyePos_, curPos_ - eyePos_);
339 oldResult.first = true;
340 curResult.first = true;
341 }
342 } else {
343 typename T::Vector_3 planeNormal(eyePos_ - sceneCenter_);
344 oldResult = findRayPlaneIntersection<T>(sceneCenter_, planeNormal,
345 eyePos_, startPos_ - eyePos_);
346 curResult = findRayPlaneIntersection<T>(sceneCenter_, planeNormal,
347 eyePos_, curPos_ - eyePos_);
348 }
349
350 // If the above calculation succeeded, apply the rotation.
351 Rotation result(typename T::Vector_3(0, 0, 1), 0);
352 if (oldResult.first && curResult.first) {
353 typename T::Vector_3 curVec = normalize(curResult.second -
354 sceneCenter_);
355 typename T::Vector_3 oldVec = normalize(oldResult.second -
356 sceneCenter_);
357 if (norm(curVec - oldVec) > 1e-20) {
358 Quaternion<T> q = Quaternion<T>(0, curVec) / Quaternion<T>(0,
359 oldVec);
360 result = quaternionToRotation(q);
361 }
362 }
363
364 if (debugLevel_ > 0) {
365 std::cerr << "result=" << result.axis << " " << result.angle << "\n";
366 }
367 return result;
368 }
369
370 template <class T>
371 typename Arcball<T>::Rotation Arcball<T>::combineRotations(
372 const Arcball<T>::Rotation& r0, const Arcball<T>::Rotation& r1)
373 {
374 return quaternionToRotation(rotationToQuaternion(r1) *
375 rotationToQuaternion(r0));
376 }
377
380
385 }
386
387 #endif
SPL::normalize
T::Vector_3 normalize(const typename CGAL::Vector_3< T > &v)
Compute a unit vector.
Definition: cgalUtil.hpp:79
SPL::Quaternion
A quaternion represented in terms of its scalar and vector parts.
Definition: cgalUtil.hpp:133
SPL::Arcball::combineRotations
static Rotation combineRotations(const Rotation &, const Rotation &)
Combine two rotations.
Definition: Arcball.hpp:371
SPL::Arcball::clear
void clear()
Clear the starting and current positions for the arcball.
Definition: Arcball.hpp:305
SPL::Arcball::setDebugLevel
void setDebugLevel(int debugLevel) const
For debugging...
SPL::Arcball::Vector
Kernel::Vector_3 Vector
The vector type.
Definition: Arcball.hpp:171
SPL
Definition: Arcball.hpp:48
SPL::Arcball::initialize
void initialize(double arcBallRadius, const Point &eyePos, const Vector &eyeDir, const Vector &eyeUp, const Point &sceneCenter)
Initialize the state of an arcball.
Definition: Arcball.hpp:262
SPL::quaternionToRotation
Rotation_3< T > quaternionToRotation(const Quaternion< T > &q)
Convert a unit-norm quaternion into its corresponding rotation.
Definition: cgalUtil.hpp:198
SPL::Arcball::Point
Kernel::Point_3 Point
The point type.
Definition: Arcball.hpp:168
SPL::norm
T::FT norm(const typename CGAL::Vector_3< T > &v)
Compute the norm of a vector.
Definition: cgalUtil.hpp:66
SPL::Arcball
Arcball.
Definition: Arcball.hpp:160
SPL::Rotation_3::angle
Real angle
The angle of rotation.
Definition: cgalUtil.hpp:124
SPL::Rotation_3
A 3-D rotation.
Definition: cgalUtil.hpp:106
SPL::rotationToQuaternion
Quaternion< T > rotationToQuaternion(const Rotation_3< T > &rot)
Convert a rotation into its corresponding quaternion.
Definition: cgalUtil.hpp:187
SPL::Arcball::start
void start(const Point &pos)
Set the starting position for arcball movement.
Definition: Arcball.hpp:283
SPL::findRayPlaneIntersection
std::pair< bool, typename T::Point_3 > findRayPlaneIntersection(const typename CGAL::Point_3< T > &planePoint, const typename CGAL::Vector_3< T > &planeNormal, const typename CGAL::Point_3< T > &rayOrigin, const typename CGAL::Vector_3< T > &rayDir)
Compute the intersection of a ray and a plane.
Definition: Arcball.hpp:132
SPL::Arcball::Kernel
T Kernel
The CGAL kernel.
Definition: Arcball.hpp:165
SPL::Arcball::move
void move(const Point &pos)
Set the current position for arcball movement.
Definition: Arcball.hpp:295
SPL::Arcball::Rotation
Rotation_3< Kernel > Rotation
The representation of a rotation.
Definition: Arcball.hpp:174
SPL::findRaySphereIntersection
std::pair< bool, typename T::Point_3 > findRaySphereIntersection(const typename CGAL::Point_3< T > &sphereCenter, typename T::FT sphereRadius, const typename CGAL::Point_3< T > &rayOrigin, const typename CGAL::Vector_3< T > &rayDir)
Compute the intersection of a ray and a sphere.
Definition: Arcball.hpp:90
SPL::Arcball::Arcball
Arcball()
Create an arcball.
Definition: Arcball.hpp:255
SPL::Arcball::getRotation
Rotation getRotation() const
Get the rotation required to turn the arcball from the starting position to the current position...
Definition: Arcball.hpp:317
SPL::Arcball::setMode
void setMode(int mode)
Set the arcball rotation mode.
Definition: Arcball.hpp:277
SPL::Rotation_3::axis
Vector_3 axis
The axis of rotation.
Definition: cgalUtil.hpp:121
SPL::closestPointOnRay
T::Point_3 closestPointOnRay(const typename CGAL::Point_3< T > &rayOrigin, const typename CGAL::Vector_3< T > &rayDir, const typename CGAL::Point_3< T > &point)
Compute the closest point on a ray to the specified point.
Definition: Arcball.hpp:64
cgalUtil.hpp
This file contains various CGAL utility code.