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