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 SbCylinderSectionProjector SbCylinderSectionProjector.h Inventor/projectors/SbCylinderSectionProjector.h
35 \brief The SbCylinderSectionProjector projects 2D points to a sliced cylinder.
36
37 \ingroup projectors
38
39 The projection cylinder for this class is sliced by a clipping plane
40 parallel to its height axis. Projections will be mapped to the
41 remaining cylinder part.
42
43 \sa SbSphereSectionProjector
44 */
45
46 #include <Inventor/projectors/SbCylinderSectionProjector.h>
47 #include <cfloat>
48
49 #if COIN_DEBUG
50 #include <Inventor/errors/SoDebugError.h>
51 #endif // COIN_DEBUG
52
53 /*! \var SbCylinderSectionProjector::tolerance
54 Tolerance value, deciding how much of the half-cylinder to do
55 projections against.
56 */
57 /*! \var SbCylinderSectionProjector::tolDist
58 Tolerance value multiplied with the cylinder radius.
59 */
60 /*! \var SbCylinderSectionProjector::tolPlane
61 Defines the plane cutting the cylinder into a projection part.
62 */
63 /*! \var SbCylinderSectionProjector::planeDir
64 Direction of cutting plane.
65 */
66 /*! \var SbCylinderSectionProjector::planeLine
67 A line within the plane which is parallel to the cylinder axis.
68 */
69 /*! \var SbCylinderSectionProjector::planeDist
70 Distance from plane to cylinder axis.
71 */
72
73
74 /*!
75 Default constructor. See SbCylinderProjector::SbCylinderProjector().
76
77 The \a edgetol value should be within <0, 1], and specifies how much
78 of the cylinder is used as a projection surface. 1.0 means the full
79 front half is used.
80 */
SbCylinderSectionProjector(const float edgetol,const SbBool orienttoeye)81 SbCylinderSectionProjector::SbCylinderSectionProjector(const float edgetol,
82 const SbBool orienttoeye)
83 : SbCylinderProjector(orienttoeye),
84 tolerance(edgetol)
85 {
86 this->needSetup = TRUE;
87 }
88
89 /*!
90 Constructor with explicit setting of the projection cylinder.
91 */
SbCylinderSectionProjector(const SbCylinder & cyl,const float edgetol,const SbBool orienttoeye)92 SbCylinderSectionProjector::SbCylinderSectionProjector(const SbCylinder & cyl,
93 const float edgetol,
94 const SbBool orienttoeye)
95 : inherited(cyl, orienttoeye),
96 tolerance(edgetol)
97 {
98 this->needSetup = TRUE;
99 }
100
101 // Documented in superclass.
102 SbProjector *
copy(void) const103 SbCylinderSectionProjector::copy(void) const
104 {
105 return new SbCylinderSectionProjector(*this);
106 }
107
108 // Documented in superclass.
109 SbVec3f
project(const SbVec2f & point)110 SbCylinderSectionProjector::project(const SbVec2f & point)
111 {
112 if (this->needSetup) this->setupTolerance();
113
114 SbLine projline = this->getWorkingLine(point);
115 SbVec3f projpt;
116
117 SbBool tst = this->intersectCylinderFront(projline, projpt);
118 if (!tst || !this->isWithinTolerance(projpt)) {
119 if (!this->tolPlane.intersect(projline, projpt)) {
120 #if COIN_DEBUG
121 SoDebugError::postWarning("SbCylinderSectionProjector::project",
122 "working line is parallel to cylinder axis.");
123 #endif // COIN_DEBUG
124 // set to 0, 0, 0 to avoid crazy rotations. lastPoint will then
125 // never change, and there will be no rotation in getRotation()
126 projpt = SbVec3f(0.0f, 0.0f, 0.0f);
127 }
128 else {
129 SbVec3f ptOnLine = this->planeLine.getClosestPoint(projpt);
130 SbLine myLine(projpt, ptOnLine);
131 if (!this->cylinder.intersect(myLine, projpt)) {
132 // shouldn't happen, but be robust if it does
133 projpt = SbVec3f(0.0f, 0.0f, 0.0f);
134 }
135 }
136 }
137
138 this->lastPoint = projpt;
139 return projpt;
140 }
141
142 // Documented in superclass.
143 SbRotation
getRotation(const SbVec3f & point1,const SbVec3f & point2)144 SbCylinderSectionProjector::getRotation(const SbVec3f & point1,
145 const SbVec3f & point2)
146 {
147 const SbLine & axis = this->cylinder.getAxis();
148 SbVec3f v1 = point1 - axis.getClosestPoint(point1);
149 SbVec3f v2 = point2 - axis.getClosestPoint(point2);
150
151 SbRotation rot(v1, v2); // rotate vector v1 into vector v2
152
153 // this is to make sure rotation only happens around cylinder axis
154 SbVec3f dummy;
155 float angle;
156 rot.getValue(dummy, angle);
157
158 if (dummy.dot(axis.getDirection()) > 0.0f)
159 return SbRotation(axis.getDirection(), angle);
160 else
161 return SbRotation(axis.getDirection(), -angle);
162 }
163
164 /*!
165 The \a edgetol value decides how much of the surface of the cylinder
166 is used for projection. 1.0 means the full cylinder half is used.
167 */
168 void
setTolerance(const float edgetol)169 SbCylinderSectionProjector::setTolerance(const float edgetol)
170 {
171 #if COIN_DEBUG // COIN_DEBUG
172 if (edgetol <= 0.0f || edgetol > 1.0f) {
173 SoDebugError::postWarning("SbCylinderSectionProjector::setTolerance",
174 "edge tolerance should be within <0, 1].");
175 }
176 #endif // COIN_DEBUG
177 this->tolerance = edgetol;
178 this->needSetup = TRUE;
179 }
180
181 /*!
182 Returns edge tolerance for the cylinder half.
183 */
184 float
getTolerance(void) const185 SbCylinderSectionProjector::getTolerance(void) const
186 {
187 return this->tolerance;
188 }
189
190 /*!
191 Check if \a point is within the part of the cylinder used for
192 projections.
193 */
194 SbBool
isWithinTolerance(const SbVec3f & point)195 SbCylinderSectionProjector::isWithinTolerance(const SbVec3f & point)
196 {
197 if (this->needSetup) this->setupTolerance();
198
199 // check if behind tolerance plane
200 if (!this->tolPlane.isInHalfSpace(point)) return FALSE;
201
202 SbVec3f ptonline = this->planeLine.getClosestPoint(point);
203 if ((ptonline-point).sqrLength() > this->sqrtoldist) return FALSE;
204 return TRUE;
205 }
206
207 /*!
208 Recalculate the internal projection surface settings. Needs to be
209 done if any of the parameters influencing the projection surface
210 have been changed from subclasses without using the access methods.
211 */
212 void
setupTolerance(void)213 SbCylinderSectionProjector::setupTolerance(void)
214 {
215 SbVec3f refdir;
216 if (this->orientToEye) {
217 refdir = -this->viewVol.getProjectionDirection();
218 this->worldToWorking.multDirMatrix(refdir, refdir);
219 }
220 else {
221 refdir = SbVec3f(0.0f, 0.0f, 1.0f);
222 }
223 float radius = this->cylinder.getRadius();
224 this->tolDist = this->tolerance * radius;
225 this->sqrtoldist = this->tolDist * this->tolDist;
226 const SbLine & axis = this->cylinder.getAxis();
227 SbVec3f somept = axis.getPosition() + refdir;
228 SbVec3f ptonaxis = axis.getClosestPoint(somept);
229
230 // find plane direction perpendicular to line
231 this->planeDir = somept - ptonaxis;
232 if (this->planeDir.normalize() < FLT_EPSILON) {
233 // the cylinder axis is parallel to the view direction. This is a
234 // special case, and not really supported by the projector. Just
235 // create a tilted plane to make it possible to rotate the
236 // cylinder even for this case.
237 this->planeDir = this->viewVol.getViewUp() +
238 this->viewVol.getProjectionDirection();
239 this->worldToWorking.multDirMatrix(this->planeDir, this->planeDir);
240 (void) this->planeDir.normalize();
241 }
242
243 if (!this->intersectFront) {
244 this->planeDir = -this->planeDir;
245 }
246 // distance from plane to cylinder axis
247 this->planeDist = (float)sqrt(radius * radius - this->tolDist * this->tolDist);
248
249 // create line parallel to axis, but in plane
250 SbVec3f linept = axis.getPosition()+this->planeDir * this->planeDist;
251 this->planeLine = SbLine(linept, linept + axis.getDirection());
252 this->tolPlane = SbPlane(this->planeDir, linept);
253
254 this->needSetup = FALSE;
255 }
256