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 SbCylinderSheetProjector SbCylinderSheetProjector.h Inventor/projectors/SbCylinderSheetProjector.h
35   \brief The SbCylinderSheetProjector class projects 2D points to 3D points on a sheet covering a cylindrical shape.
36 
37   \ingroup projectors
38  */
39 
40 // FIXME: we do not use a hyperbolic sheet, as we're supposed to do,
41 // for this class. Instead we use a straight plane. This should hardly
42 // be noticable for the user, but for correctness, a hyperbolic sheet
43 // should of course be used. 20000308 mortene.
44 
45 #include <Inventor/projectors/SbCylinderSheetProjector.h>
46 #include <cfloat> // FLT_EPSILON
47 
48 #if COIN_DEBUG
49 #include <Inventor/errors/SoDebugError.h>
50 #endif // COIN_DEBUG
51 
52 /*! \var SbCylinderSheetProjector::workingProjPoint
53   Last projected point, in the working space coordinate system.
54 */
55 /*! \var SbCylinderSheetProjector::planeDir
56   Normal vector of the plane defining the orientation of the sheet.
57 */
58 /*! \var SbCylinderSheetProjector::tolPlane
59   The tolerance value specifying how much of the cylinder is "above"
60   the sheet.
61 */
62 
63 
64 /*!
65   Constructor. Uses default cylinder defintion, see
66   SbCylinderProjector::SbCylinderProjector().
67 
68   \a orienttoeye decides whether or not the cylinder and sheet should
69   always be oriented towards the viewer.
70 */
SbCylinderSheetProjector(const SbBool orienttoeye)71 SbCylinderSheetProjector::SbCylinderSheetProjector(const SbBool orienttoeye)
72   : inherited(orienttoeye)
73 {
74 }
75 
76 /*!
77   Constructor with explicit definition of projection cylinder.
78 */
SbCylinderSheetProjector(const SbCylinder & cyl,const SbBool orienttoeye)79 SbCylinderSheetProjector::SbCylinderSheetProjector(const SbCylinder & cyl,
80                                                    const SbBool orienttoeye)
81   : inherited(cyl, orienttoeye)
82 {
83 }
84 
85 // Documented in superclass.
86 SbProjector *
copy(void) const87 SbCylinderSheetProjector::copy(void) const
88 {
89   return new SbCylinderSheetProjector(*this);
90 }
91 
92 // Documented in superclass.
93 SbVec3f
project(const SbVec2f & point)94 SbCylinderSheetProjector::project(const SbVec2f & point)
95 {
96   if (this->needSetup) this->setupPlane();
97 
98   SbLine projline = this->getWorkingLine(point);
99   SbVec3f projpt;
100 
101   // FIXME: add code to intersect hyperbolic sheet (see code in
102   // SbSphereSheetProjector).
103   //
104   // Here's a complete, stand-alone example that can be used while
105   // testing projection. It projects a grid on top of the
106   // SbCylinderSheetProjector and spits out an iv-file with an
107   // SoPointSet that shows off how the sheet will look:
108   //
109   //
110   // -----8<--- [snip] -----8<--- [snip] -----8<--- [snip] ---
111   // #include <cstdio>
112   // #include <Inventor/SbLinear.h>
113   // #include <Inventor/projectors/SbCylinderSheetProjector.h>
114   // #include <Inventor/SoDB.h>
115   //
116   // int
117   // main(void)
118   // {
119   //   SoDB::init();
120   //
121   //   const float START = 0.0f;
122   //   const float END = 1.0f;
123   //   const float STEPS = 50.0f;
124   //   const float STEPSIZE = ((END - START) / STEPS);
125   //
126   //   SbCylinderSheetProjector ssp;
127   //
128   //   SbViewVolume volume;
129   //   volume.ortho(-1, 1, -1, 1, -1, 1);
130   //   ssp.setViewVolume(volume);
131   //
132   //   (void)fprintf(stdout, "#Inventor V2.1 ascii\n\n"
133   //                 "Separator {\n"
134   //                 "  Coordinate3 {\n"
135   //                 "    point [\n");
136   //
137   //   for (float i=START; i <= END; i += STEPSIZE) {
138   //     for (float j=START; j <= END; j += STEPSIZE) {
139   //       SbVec3f v = ssp.project(SbVec2f(j, i));
140   //       (void)fprintf(stdout, "\t%f %f %f,\n", v[0], v[1], v[2]);
141   //     }
142   //   }
143   //
144   //   (void)fprintf(stdout, "      ]\n"
145   //                 "    }\n"
146   //                 "  DrawStyle { pointSize 2 }\n"
147   //                 "  PointSet { }\n"
148   //                 "}\n");
149   //
150   //   return 0;
151   // }
152   // -----8<--- [snip] -----8<--- [snip] -----8<--- [snip] ---
153 
154   SbBool tst = this->intersectCylinderFront(projline, projpt);
155   if (!tst) {
156     if (!this->tolPlane.intersect(projline, projpt)) {
157 #if COIN_DEBUG
158       SoDebugError::postWarning("SbCylinderSheetProjector::project",
159                                 "working line is parallel to cylinder axis.");
160 #endif // COIN_DEBUG
161       return SbVec3f(0.0f, 0.0f, 0.0f);
162     }
163   }
164   this->lastPoint = projpt;
165   this->workingProjPoint = projpt; // FIXME: investigate (pederb)
166   return projpt;
167 }
168 
169 // Documented in superclass.
170 SbRotation
getRotation(const SbVec3f & point1,const SbVec3f & point2)171 SbCylinderSheetProjector::getRotation(const SbVec3f & point1,
172                                       const SbVec3f & point2)
173 {
174   const SbLine & axis = this->cylinder.getAxis();
175   SbVec3f v1 = point1 - axis.getClosestPoint(point1);
176   SbVec3f v2 = point2 - axis.getClosestPoint(point2);
177   SbRotation rot(v1, v2); // rotate vector v1 into vector v2
178 
179   // FIXME: add rotation from sheet (pederb)
180 
181   SbVec3f dummy;
182   float angle;
183   rot.getValue(dummy, angle);
184 
185   if (dummy.dot(axis.getDirection()) > 0.0f)
186     return SbRotation(axis.getDirection(), angle);
187   return SbRotation(axis.getDirection(), -angle);
188 }
189 
190 /*!
191   Recalculates projection surface settings after changes to the
192   parameters.
193 */
194 void
setupPlane(void)195 SbCylinderSheetProjector::setupPlane(void)
196 {
197   const SbLine & axis = this->cylinder.getAxis();
198   SbVec3f refDir;
199   if (this->orientToEye) {
200     refDir = -this->viewVol.getProjectionDirection();
201     this->worldToWorking.multDirMatrix(refDir, refDir);
202   }
203   else {
204     refDir = SbVec3f(0.0f, 0.0f, 1.0f);
205   }
206   SbVec3f somePt = axis.getPosition() + refDir;
207   SbVec3f ptOnAxis = axis.getClosestPoint(somePt);
208 
209   this->planeDir = somePt - ptOnAxis;
210 
211   if (this->planeDir.normalize() < FLT_EPSILON) {
212     // the cylinder axis is parallel to the view direction. This is a
213     // special case, and not really supported by the projector. Just
214     // create a tilted plane to make it possible to rotate the
215     // cylinder even for this case.
216     this->planeDir = this->viewVol.getViewUp() +
217       this->viewVol.getProjectionDirection();
218     this->worldToWorking.multDirMatrix(this->planeDir, this->planeDir);
219     (void) this->planeDir.normalize();
220   }
221 
222   if (!this->intersectFront) this->planeDir = -this->planeDir;
223 
224   this->tolPlane = SbPlane(this->planeDir, axis.getPosition());
225   this->needSetup = FALSE;
226 }
227