root/OpenSceneGraph/trunk/src/osgManipulator/Projector.cpp @ 13041

Revision 13041, 21.1 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.
14
15#include <osgManipulator/Projector>
16
17using namespace osgManipulator;
18
19// When the squared magnitude (length2) of the cross product of 2
20// angles is less than this tolerance, they are considered parallel.
21// osg::Vec3 a, b; (a ^ b).length2()
22#define CROSS_PRODUCT_ANGLE_TOLERANCE 1.0e-1
23
24namespace
25{
26
27bool computeClosestPoints(const osg::LineSegment& l1, const osg::LineSegment& l2,
28                          osg::Vec3d& p1, osg::Vec3d& p2)
29{
30    // Computes the closest points (p1 and p2 on line l1 and l2 respectively) between the two lines
31    // An explanation of the algorithm can be found at
32    // http://www.geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm
33
34    osg::LineSegment::vec_type u = l1.end() - l1.start(); u.normalize();
35    osg::LineSegment::vec_type v = l2.end() - l2.start(); v.normalize();
36
37    osg::LineSegment::vec_type w0 = l1.start() - l2.start();
38
39    double a = u * u;
40    double b = u * v;
41    double c = v * v;
42    double d = u * w0;
43    double e = v * w0;
44
45    double denominator = a*c - b*b;
46
47    // Test if lines are parallel
48    if (denominator == 0.0) return false;
49
50    double sc = (b*e - c*d)/denominator;
51    double tc = (a*e - b*d)/denominator;
52
53    p1 = l1.start() + u * sc;
54    p2 = l2.start() + v * tc;
55
56    return true;
57}
58
59bool computeClosestPointOnLine(const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd,
60                               const osg::Vec3d& fromPoint, osg::Vec3d& closestPoint)
61{
62    osg::Vec3d v = lineEnd - lineStart;
63    osg::Vec3d w = fromPoint - lineStart;
64
65    double c1 = w * v;
66    double c2 = v * v;
67
68    double almostZero = 0.000001;
69    if (c2 < almostZero) return false;
70
71    double b = c1 / c2;
72    closestPoint = lineStart + v * b;
73
74    return true;
75}
76
77bool getPlaneLineIntersection(const osg::Vec4d& plane,
78                              const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd,
79                              osg::Vec3d& isect)
80{
81    const double deltaX = lineEnd.x() - lineStart.x();
82    const double deltaY = lineEnd.y() - lineStart.y();
83    const double deltaZ = lineEnd.z() - lineStart.z();
84
85    const double denominator = (plane[0]*deltaX + plane[1]*deltaY + plane[2]*deltaZ);
86    if (! denominator) return false;
87
88    const double C = (plane[0]*lineStart.x() + plane[1]*lineStart.y() + plane[2]*lineStart.z() + plane[3]) / denominator;
89
90    isect.x() = lineStart.x() - deltaX * C;
91    isect.y() = lineStart.y() - deltaY * C;
92    isect.z() = lineStart.z() - deltaZ * C;
93
94    return true;
95}
96
97bool getSphereLineIntersection(const osg::Sphere& sphere,
98                               const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd,
99                               osg::Vec3d& frontISect, osg::Vec3d& backISect)
100{
101    osg::Vec3d lineDirection = lineEnd - lineStart;
102    lineDirection.normalize();
103
104    osg::Vec3d v = lineStart - sphere.getCenter();
105    double B = 2.0f * (lineDirection * v);
106    double C = v * v - sphere.getRadius() * sphere.getRadius();
107
108    double discriminant = B * B - 4.0f * C;
109
110    if (discriminant < 0.0f) // Line and sphere don't intersect.
111        return false;
112
113    double discriminantSqroot = sqrtf(discriminant);
114    double t0 = (-B - discriminantSqroot) * 0.5f;
115    frontISect = lineStart + lineDirection * t0;
116
117    double t1 = (-B + discriminantSqroot) * 0.5f;
118    backISect = lineStart + lineDirection * t1;
119
120    return true;
121}
122
123bool getUnitCylinderLineIntersection(const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd,
124                                     osg::Vec3d& isectFront, osg::Vec3d& isectBack)
125{
126    osg::Vec3d dir = lineEnd - lineStart;
127    dir.normalize();
128
129    double a = dir[0] * dir[0] + dir[1] * dir[1];
130    double b = 2.0f * (lineStart[0] * dir[0] + lineStart[1] * dir[1]);
131    double c = lineStart[0] * lineStart[0] + lineStart[1] * lineStart[1] - 1;
132
133    double d = b*b - 4*a*c;
134    if (d < 0.0f) return false;
135
136    double dSqroot = sqrtf(d);
137    double t0, t1;
138    if (b > 0.0f)
139    {
140        t0 = -(2.0f * c) / (dSqroot + b);
141        t1 = -(dSqroot + b) / (2.0 * a);
142    }
143    else
144    {
145        t0 = (2.0f * c) / (dSqroot - b);
146        t1 = (dSqroot - b) / (2.0 * a);
147    }
148
149    isectFront = lineStart + dir * t0;
150    isectBack = lineStart + dir * t1;
151    return true;
152}
153
154bool getCylinderLineIntersection(const osg::Cylinder& cylinder,
155                                 const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd,
156                                 osg::Vec3d& isectFront, osg::Vec3d& isectBack)
157{
158    // Compute matrix transformation that takes the cylinder to a unit cylinder with Z-axis as it's axis and
159    // (0,0,0) as it's center.
160    double oneOverRadius = 1.0f / cylinder.getRadius();
161    osg::Matrix toUnitCylInZ = osg::Matrix::translate(-cylinder.getCenter())
162                               * osg::Matrix::scale(oneOverRadius, oneOverRadius, oneOverRadius)
163                               * osg::Matrix(cylinder.getRotation().inverse());
164
165    // Transform the lineStart and lineEnd into the unit cylinder space.
166    osg::Vec3d unitCylLineStart = lineStart * toUnitCylInZ;
167    osg::Vec3d unitCylLineEnd   = lineEnd * toUnitCylInZ;
168
169    // Intersect line with unit cylinder.
170    osg::Vec3d unitCylIsectFront, unitCylIsectBack;
171    if (! getUnitCylinderLineIntersection(unitCylLineStart, unitCylLineEnd, unitCylIsectFront, unitCylIsectBack))
172        return false;
173
174    // Transform back from unit cylinder space.
175    osg::Matrix invToUnitCylInZ(osg::Matrix::inverse(toUnitCylInZ));
176    isectFront = unitCylIsectFront * invToUnitCylInZ;
177    isectBack = unitCylIsectBack * invToUnitCylInZ;
178
179    return true;
180}
181
182osg::Vec3d getLocalEyeDirection(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld)
183{
184    // To take a normal from world to local you need to transform it by the transpose of the inverse of the
185    // world to local matrix. Pre-multiplying is equivalent to doing a post-multiplication of the transpose.
186    osg::Vec3d localEyeDir = localToWorld * eyeDir;
187    localEyeDir.normalize();
188    return localEyeDir;
189}
190
191osg::Plane computePlaneThruPointAndOrientedToEye(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld,
192                                                 const osg::Vec3d& point, bool front)
193{
194    osg::Vec3d planeNormal = getLocalEyeDirection(eyeDir, localToWorld);
195    if (! front) planeNormal = -planeNormal;
196
197    osg::Plane plane;
198    plane.set(planeNormal, point);
199    return plane;
200}
201
202// Computes a plane to be used as a basis for determining a displacement.  When eyeDir is close
203// to the cylinder axis, then the plane will be set to be perpendicular to the cylinder axis.
204// Otherwise it will be set to be parallel to the cylinder axis and oriented towards eyeDir.
205osg::Plane computeIntersectionPlane(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld,
206                                    const osg::Vec3d& axisDir, const osg::Cylinder& cylinder,
207                                    osg::Vec3d& planeLineStart, osg::Vec3d& planeLineEnd,
208                                    bool& parallelPlane, bool front)
209{
210    osg::Plane plane;
211
212    osg::Vec3d unitAxisDir = axisDir;
213    unitAxisDir.normalize();
214    osg::Vec3d perpDir = unitAxisDir ^ getLocalEyeDirection(eyeDir, localToWorld);
215
216    // Check to make sure eye and cylinder axis are not too close
217    if(perpDir.length2() < CROSS_PRODUCT_ANGLE_TOLERANCE)
218    {
219        // Too close, so instead return plane perpendicular to cylinder axis.
220        plane.set(unitAxisDir, cylinder.getCenter());
221        parallelPlane = false;
222        return plane;
223    }
224
225    // Otherwise compute plane along axisDir oriented towards eye
226    osg::Vec3d planeDir = perpDir ^ axisDir;
227    planeDir.normalize();
228    if (! front)
229        planeDir = -planeDir;
230
231    osg::Vec3d planePoint = planeDir * cylinder.getRadius() + axisDir;
232    plane.set(planeDir, planePoint);
233
234    planeLineStart = planePoint;
235    planeLineEnd = planePoint + axisDir;
236    parallelPlane = true;
237    return plane;
238}
239
240} // namespace
241
242
243Projector::Projector() : _worldToLocalDirty(false)
244{
245}
246
247Projector::~Projector()
248{
249}
250
251LineProjector::LineProjector()
252{
253    _line = new osg::LineSegment(osg::LineSegment::vec_type(0.0,0.0,0.0), osg::LineSegment::vec_type(1.0,0.0,0.0));
254}
255
256LineProjector::LineProjector(const osg::LineSegment::vec_type& s, const osg::LineSegment::vec_type& e)
257{
258    _line = new osg::LineSegment(s,e);
259}
260
261LineProjector::~LineProjector()
262{
263}
264
265bool LineProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
266{
267    if (!_line->valid())
268    {
269        OSG_WARN << "Warning: Invalid line set. LineProjector::project() failed."<<std::endl;
270        return false;
271    }
272
273    // Transform the line to world/object coordinate space.
274    osg::ref_ptr<osg::LineSegment> objectLine = new osg::LineSegment;
275    objectLine->mult(*_line, getLocalToWorld());
276
277    // Get the near and far points for the mouse point.
278    osg::Vec3d nearPoint, farPoint;
279    pi.getNearFarPoints(nearPoint,farPoint);
280    osg::ref_ptr<osg::LineSegment> pointerLine = new osg::LineSegment(nearPoint,farPoint);
281
282    osg::Vec3d closestPtLine, closestPtProjWorkingLine;
283    if (! computeClosestPoints(*objectLine, *pointerLine, closestPtLine, closestPtProjWorkingLine))
284        return false;
285
286    osg::Vec3d localClosestPtLine = closestPtLine * getWorldToLocal();
287
288    projectedPoint = localClosestPtLine;
289
290    return true;
291}
292
293PlaneProjector::PlaneProjector()
294{
295}
296
297PlaneProjector::PlaneProjector(const osg::Plane& plane)
298{
299    _plane = plane;
300}
301
302
303PlaneProjector::~PlaneProjector()
304{
305}
306
307bool PlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
308{
309    if (!_plane.valid())
310    {
311        OSG_WARN << "Warning: Invalid plane set. PlaneProjector::project() failed."<< std::endl;
312        return false;
313    }
314
315    // Get the near and far points for the mouse point.
316    osg::Vec3d nearPoint, farPoint;
317    pi.getNearFarPoints(nearPoint,farPoint);
318
319    // Transform these points into local coordinates.
320    osg::Vec3d objectNearPoint, objectFarPoint;
321    objectNearPoint = nearPoint * getWorldToLocal();
322    objectFarPoint  = farPoint * getWorldToLocal();
323
324    // Find the intersection of the plane with the line (formed by the near and far points in local coordinates).
325    return getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, projectedPoint);
326}
327
328
329SphereProjector::SphereProjector() : _sphere(new osg::Sphere), _front(true)
330{
331}
332
333SphereProjector::SphereProjector(osg::Sphere* sphere) : _sphere(sphere), _front(true)
334{
335}
336
337
338SphereProjector::~SphereProjector()
339{
340}
341
342bool SphereProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
343{
344    if (!_sphere->valid())
345    {
346        OSG_WARN << "Warning: Invalid sphere. SphereProjector::project() failed." << std::endl;
347        return false;
348    }
349
350    // Get the near and far points for the mouse point.
351    osg::Vec3d nearPoint, farPoint;
352    pi.getNearFarPoints(nearPoint,farPoint);
353
354    // Transform these points into local coordinates.
355    osg::Vec3d objectNearPoint, objectFarPoint;
356    objectNearPoint = nearPoint * getWorldToLocal();
357    objectFarPoint  = farPoint * getWorldToLocal();
358
359    // Find the intersection of the sphere with the line.
360    osg::Vec3d dontCare;
361    if (_front)
362        return getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, projectedPoint, dontCare);
363    return getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, dontCare, projectedPoint);
364}
365
366bool SphereProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix& localToWorld) const
367{
368    osg::Vec3d centerToPoint = getSphere()->getCenter() - pi.getLocalIntersectPoint();
369    if (centerToPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0)
370        return false;
371    return true;
372}
373
374
375SpherePlaneProjector::SpherePlaneProjector()
376{
377}
378
379SpherePlaneProjector::SpherePlaneProjector(osg::Sphere* sphere) : SphereProjector(sphere)
380{
381}
382
383
384SpherePlaneProjector::~SpherePlaneProjector()
385{
386}
387
388osg::Quat SpherePlaneProjector::getRotation(const osg::Vec3d& p1, bool p1OnSphere, const osg::Vec3d& p2, bool p2OnSphere,
389                                            float radialFactor) const
390{
391    if (p1OnSphere && p2OnSphere)
392    {
393        osg::Quat rotation;
394        if (_front)
395            rotation.makeRotate(p1 - getSphere()->getCenter(), p2 - getSphere()->getCenter());
396        else
397            rotation.makeRotate(p2 - getSphere()->getCenter(), p1 - getSphere()->getCenter());
398        return rotation;
399    }
400    else if (!p1OnSphere && !p2OnSphere)
401    {
402        osg::Quat rotation;
403        rotation.makeRotate(p1 - getSphere()->getCenter(), p2 - getSphere()->getCenter());
404
405        osg::Vec3d axis; double angle;
406        rotation.getRotate(angle, axis);
407
408        osg::Vec3d realAxis;
409        if (axis * _plane.getNormal() > 0.0f)
410            realAxis = _plane.getNormal();
411        else
412            realAxis = - _plane.getNormal();
413
414        osg::Quat rollRotation(angle, realAxis);
415
416        osg::Vec3d diff1 = p1 - getSphere()->getCenter();
417        osg::Vec3d diff2 = p2 - getSphere()->getCenter();
418        double d = diff2.length() - diff1.length();
419
420        double theta = d / getSphere()->getRadius();
421        if (fabs(theta) < 0.000001 || fabs(theta) > 1.0)
422            return rollRotation;
423
424        diff1.normalize();
425        osg::Vec3d pullAxis = diff1 ^ _plane.getNormal();
426        pullAxis.normalize();
427        osg::Quat pullRotation(radialFactor * theta, pullAxis);
428
429        osg::Quat totalRotation = pullRotation * rollRotation;
430        return totalRotation;
431    }
432    else
433    {
434        const osg::Vec3d& planePoint = getSphere()->getCenter();
435
436        osg::Vec3d intersection, dontCare;
437        if (p1OnSphere)
438            getSphereLineIntersection(*getSphere(), p2, planePoint, intersection, dontCare);
439        else
440            getSphereLineIntersection(*getSphere(), p1, planePoint, intersection, dontCare);
441
442        osg::Quat rotation;
443        if (p1OnSphere)
444            rotation.makeRotate(p1 - getSphere()->getCenter(), intersection - getSphere()->getCenter());
445        else
446            rotation.makeRotate(intersection - getSphere()->getCenter(), p2 - getSphere()->getCenter());
447        return rotation;
448    }
449}
450
451bool SpherePlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
452{
453    if (!_sphere->valid())
454    {
455        OSG_WARN << "Warning: Invalid sphere. SpherePlaneProjector::project() failed." << std::endl;
456        return false;
457    }
458
459    // Get the near and far points for the mouse point.
460    osg::Vec3d nearPoint, farPoint;
461    pi.getNearFarPoints(nearPoint,farPoint);
462
463    // Transform these points into local coordinates.
464    osg::Vec3d objectNearPoint, objectFarPoint;
465    objectNearPoint = nearPoint * getWorldToLocal();
466    objectFarPoint  = farPoint * getWorldToLocal();
467
468    // Find the intersection of the sphere with the line.
469    osg::Vec3d sphereIntersection, dontCare;
470    bool hitSphere = false;
471    if (_front)
472        hitSphere = getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, sphereIntersection, dontCare);
473    else
474        hitSphere = getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, dontCare, sphereIntersection);
475
476    // Compute plane oriented to the eye.
477    _plane = computePlaneThruPointAndOrientedToEye(pi.getEyeDir(), getLocalToWorld(), getSphere()->getCenter(), _front);
478
479    // Find the intersection on the plane.
480    osg::Vec3d planeIntersection;
481    if (hitSphere)
482    {
483        if (! getPlaneLineIntersection(_plane.asVec4(), sphereIntersection, sphereIntersection + _plane.getNormal(), planeIntersection))
484            return false;
485    }
486    else
487    {
488        if (! getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, planeIntersection))
489            return false;
490    }
491
492    // Distance from the plane intersection point to the center of the sphere.
493    double dist = (planeIntersection - getSphere()->getCenter()).length();
494
495    // If the distance is less that the sphere radius choose the sphere intersection else choose
496    // the plane intersection.
497    if (dist < getSphere()->getRadius())
498    {
499        if (! hitSphere) return false;
500        projectedPoint = sphereIntersection;
501        _onSphere = true;
502    }
503    else
504    {
505        projectedPoint = planeIntersection;
506        _onSphere = false;
507    }
508    return true;
509}
510
511CylinderProjector::CylinderProjector() : _cylinder(new osg::Cylinder()), _cylinderAxis(0.0,0.0,1.0), _front(true)
512{
513}
514
515CylinderProjector::CylinderProjector(osg::Cylinder* cylinder) : _front(true)
516{
517    setCylinder(cylinder);
518}
519
520CylinderProjector::~CylinderProjector()
521{
522}
523
524bool CylinderProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
525{
526    if (!_cylinder.valid())
527    {
528        OSG_WARN << "Warning: Invalid cylinder. CylinderProjector::project() failed."
529                               << std::endl;
530        return false;
531    }
532
533    // Get the near and far points for the mouse point.
534    osg::Vec3d nearPoint, farPoint;
535    pi.getNearFarPoints(nearPoint,farPoint);
536
537    // Transform these points into local coordinates.
538    osg::Vec3d objectNearPoint, objectFarPoint;
539    objectNearPoint = nearPoint * getWorldToLocal();
540    objectFarPoint  = farPoint * getWorldToLocal();
541
542    // Find the intersection of the sphere with the line.
543    osg::Vec3d dontCare;
544    return getCylinderLineIntersection(*_cylinder, objectNearPoint, objectFarPoint, projectedPoint, dontCare);
545}
546
547bool CylinderProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix& localToWorld) const
548{
549    osg::Vec3d closestPointOnAxis;
550    computeClosestPointOnLine(getCylinder()->getCenter(), getCylinder()->getCenter() + _cylinderAxis,
551                              pi.getLocalIntersectPoint(), closestPointOnAxis);
552
553    osg::Vec3d perpPoint = pi.getLocalIntersectPoint() - closestPointOnAxis;
554    if (perpPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0)
555        return false;
556    return true;
557}
558
559CylinderPlaneProjector::CylinderPlaneProjector()
560{
561}
562
563CylinderPlaneProjector::CylinderPlaneProjector(osg::Cylinder* cylinder) : CylinderProjector(cylinder), _parallelPlane(false)
564{
565}
566
567CylinderPlaneProjector::~CylinderPlaneProjector()
568{
569}
570
571bool CylinderPlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const
572{
573    if (!_cylinder.valid())
574    {
575        OSG_WARN << "Warning: Invalid cylinder. CylinderProjector::project() failed."
576                               << std::endl;
577        return false;
578    }
579
580    // Get the near and far points for the mouse point.
581    osg::Vec3d nearPoint, farPoint;
582    pi.getNearFarPoints(nearPoint,farPoint);
583
584    // Transform these points into local coordinates.
585    osg::Vec3d objectNearPoint, objectFarPoint;
586    objectNearPoint = nearPoint * getWorldToLocal();
587    objectFarPoint  = farPoint * getWorldToLocal();
588
589    // Computes either a plane parallel to cylinder axis oriented to the eye or the plane
590    // perpendicular to the cylinder axis if the eye-cylinder angle is close.
591    _plane = computeIntersectionPlane(pi.getEyeDir(), getLocalToWorld(), _cylinderAxis,
592                                      *_cylinder, _planeLineStart, _planeLineEnd,
593                                     _parallelPlane, _front);
594
595    // Now find the point of intersection on our newly-calculated plane.
596    getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, projectedPoint);
597    return true;
598}
599
600osg::Quat CylinderPlaneProjector::getRotation(const osg::Vec3d& p1, const osg::Vec3d& p2) const
601{
602    if(_parallelPlane)
603    {
604        osg::Vec3d closestPointToPlaneLine1, closestPointToPlaneLine2;
605        computeClosestPointOnLine(_planeLineStart, _planeLineEnd,
606                                  p1, closestPointToPlaneLine1);
607        computeClosestPointOnLine(_planeLineStart, _planeLineEnd,
608                                  p2, closestPointToPlaneLine2);
609
610        osg::Vec3d v1 = p1 - closestPointToPlaneLine1;
611        osg::Vec3d v2 = p2 - closestPointToPlaneLine2;
612
613        osg::Vec3d diff = v2 - v1;
614        double d = diff.length();
615
616        // The amount of rotation is inversely proportional to the size of the cylinder
617        double angle = (getCylinder()->getRadius() == 0.0) ? 0.0 : (d / getCylinder()->getRadius());
618        osg::Vec3d rotAxis = _plane.getNormal() ^ v1;
619
620        if (v2.length() > v1.length())
621           return osg::Quat(angle, rotAxis);
622        else
623           return osg::Quat(-angle, rotAxis);
624    }
625    else
626    {
627        osg::Vec3d v1 = p1 - getCylinder()->getCenter();
628        osg::Vec3d v2 = p2 - getCylinder()->getCenter();
629
630        double cosAngle = v1 * v2 / (v1.length() * v2.length());
631
632        if (cosAngle > 1.0 || cosAngle < -1.0)
633            return osg::Quat();
634
635        double angle = acosf(cosAngle);
636        osg::Vec3d rotAxis = v1 ^ v2;
637
638        return osg::Quat(angle, rotAxis);
639    }
640}
Note: See TracBrowser for help on using the browser.