1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SbSpherePlaneProjector SbSpherePlaneProjector.h Inventor/projectors/SbSpherePlaneProjector.h
35   \brief The SbSpherePlaneProjector class projects 2D points to a half-sphere and a plane.
36 
37   \ingroup projectors
38 
39   This projector uses a plane along with the half-sphere of
40   SbSphereSectionProjector for projections. If the 2D point mapping
41   "misses" the sphere section, the 3D point will be projected onto
42   the plane.
43 
44   \sa SbCylinderPlaneProjector
45  */
46 
47 #include <Inventor/projectors/SbSpherePlaneProjector.h>
48 
49 #if COIN_DEBUG
50 #include <Inventor/errors/SoDebugError.h>
51 #endif // COIN_DEBUG
52 
53 
54 /*!
55   Default constructor. See
56   SbSphereSectionProjector::SbSphereSectionProjector().
57 */
SbSpherePlaneProjector(const float edgetol,const SbBool orienttoeye)58 SbSpherePlaneProjector::SbSpherePlaneProjector(const float edgetol,
59                                                const SbBool orienttoeye)
60   : inherited(edgetol, orienttoeye)
61 {
62 }
63 
64 /*!
65   Constructor with explicit specification of projection sphere.
66 */
SbSpherePlaneProjector(const SbSphere & sph,const float edgetol,const SbBool orienttoeye)67 SbSpherePlaneProjector::SbSpherePlaneProjector(const SbSphere & sph,
68                                                const float edgetol,
69                                                const SbBool orienttoeye)
70   : inherited(sph, edgetol, orienttoeye)
71 {
72 }
73 
74 // Documented in superclass.
75 SbProjector *
copy(void) const76 SbSpherePlaneProjector::copy(void) const
77 {
78   return new SbSpherePlaneProjector(*this);
79 }
80 
81 // Documented in superclass.
82 SbVec3f
project(const SbVec2f & point)83 SbSpherePlaneProjector::project(const SbVec2f & point)
84 {
85   if (this->needSetup) this->setupTolerance();
86 
87   SbLine projline = this->getWorkingLine(point);
88   SbVec3f projpt;
89 
90   SbBool tst = this->intersectSphereFront(projline, projpt);
91   if (!tst || !this->isWithinTolerance(projpt)) {
92     if (!this->tolPlane.intersect(projline, projpt)) {
93 #if COIN_DEBUG
94       SoDebugError::postWarning("SbSphereSectionProjector::project",
95                                 "working line is perpendicular to plane direction.");
96 #endif // COIN_DEBUG
97       // set to 0, 0, 0 to avoid crazy rotations. lastPoint will then
98       // never change, and there will be no rotation in getRotation()
99       projpt = SbVec3f(0.0f, 0.0f, 0.0f);
100     }
101   }
102   this->lastPoint = projpt;
103   return projpt;
104 }
105 
106 // Documented in superclass.
107 SbRotation
getRotation(const SbVec3f & point1,const SbVec3f & point2)108 SbSpherePlaneProjector::getRotation(const SbVec3f & point1,
109                                     const SbVec3f & point2)
110 {
111   return this->getRotation(point1, this->isWithinTolerance(point1),
112                            point2, this->isWithinTolerance(point2));
113 }
114 
115 /*!
116   Calculates rotation from \a point1 to \a point2, with \a tol1 and \a
117   tol2 deciding whether or not to use the tolerance setting.
118 */
119 SbRotation
getRotation(const SbVec3f & point1,const SbBool tol1,const SbVec3f & point2,const SbBool tol2)120 SbSpherePlaneProjector::getRotation(const SbVec3f & point1, const SbBool tol1,
121                                     const SbVec3f & point2, const SbBool tol2)
122 {
123   if (tol1 && tol2) return inherited::getRotation(point1, point2);
124   SbVec3f vec = point2 - point1;
125   SbVec3f axis = vec.cross(this->planeDir);
126   if (axis.normalize() == 0.0f) {
127 #if COIN_DEBUG
128     SoDebugError::postWarning("SbSpherePlaneProjector::getRotation",
129                               "Unable to find rotation axis.");
130 #endif // COIN_DEBUG
131     return SbRotation::identity();
132   }
133 
134   float angle = 0.0f;
135 
136   if (!tol1 && !tol2) {
137     // FIXME: this might not be 100% correct in all cases, but
138     // I doubt anyone will notice :-) pederb, 20000220
139     angle = vec.length() / this->sphere.getRadius();
140   }
141   else {
142     SbVec3f planePt;
143     SbVec3f spherePt;
144     if (!tol1) {
145       planePt = point1;
146       spherePt = point2;
147     }
148     else {
149       planePt = point2;
150       spherePt = point1;
151     }
152 
153     SbVec3f dir = planePt - this->planePoint;
154     if (dir.normalize() == 0.0f) {
155       // no movement = no rotation
156       return SbRotation::identity();
157     }
158     SbVec3f tolpt = this->planePoint + dir * this->tolDist;
159     SbVec3f vec1 = tolpt - this->sphere.getCenter();
160     SbVec3f vec2 = spherePt - this->sphere.getCenter();
161     if (vec1.normalize() == 0.0f || vec2.normalize() == 0.0f) {
162 #if COIN_DEBUG
163       SoDebugError::postWarning("SbSpherePlaneProjector::getRotation",
164                                 "Unable to find angle on projection sphere.");
165 #endif // COIN_DEBUG
166       return SbRotation::identity();
167     }
168     float cosval = vec1.dot(vec2);
169     if (cosval > 1.0f) cosval = 1.0f;
170     else if (cosval < -1.0f) cosval = -1.0f;
171     // rotation on sphere
172     angle = (float)acos(cosval);
173     // rotation caused by dragging plane
174     angle += (tolpt-planePt).length() / this->sphere.getRadius();
175   }
176   return SbRotation(axis, -angle);
177 }
178