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 SoUnits SoUnits.h Inventor/nodes/SoUnits.h
35   \brief The SoUnits class is a node for setting unit types.
36 
37   \ingroup nodes
38 
39   Even though Coin doesn't care what units you are using in your scene
40   graph \e per \e se, there's an advantage to using SoUnits nodes: you
41   have a way to split your scene graph into different "conceptual"
42   parts.
43 
44   When encountering SoUnit nodes, the traversal actions methods makes
45   sure the following geometry is scaled accordingly.
46 
47   <b>FILE FORMAT/DEFAULTS:</b>
48   \code
49     Units {
50         units METERS
51     }
52   \endcode
53 */
54 
55 // *************************************************************************
56 
57 #include <Inventor/nodes/SoUnits.h>
58 
59 #include <Inventor/actions/SoGetBoundingBoxAction.h>
60 #include <Inventor/actions/SoGLRenderAction.h>
61 #include <Inventor/actions/SoPickAction.h>
62 #include <Inventor/actions/SoCallbackAction.h>
63 #include <Inventor/actions/SoGetMatrixAction.h>
64 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
65 
66 #include <Inventor/elements/SoModelMatrixElement.h>
67 #include <Inventor/elements/SoUnitsElement.h>
68 
69 #include "nodes/SoSubNodeP.h"
70 
71 // *************************************************************************
72 
73 /*!
74   \enum SoUnits::Units
75 
76   Enumerates the available unit settings.
77 */
78 
79 
80 /*!
81   \var SoSFEnum SoUnits::units
82 
83   The units which will be used for nodes following this node in the
84   traversal (until the next SoUnit node, if any). Default value of the
85   field is SoUnits::METERS.
86 */
87 
88 
89 // *************************************************************************
90 
91 static const float factors[] = {
92   1.0f, // METERS
93   0.01f, // CENTIMETERS
94   0.001f, // MILLIMETERS
95   0.000001f, // MICROMETERS
96   0.000001f, // MICRONS
97   0.000000001f, // NANOMETERS
98   0.0000000001f, // ANGSTROMS
99   1000.0f, // KILOMETERS
100   0.3048f, // FEET
101   0.0254f, // INCHES
102   3.52777737e-4f, // POINTS
103   0.9144f, // YARDS
104   1609.3f, // MILES
105   1852.0f, // NAUTICAL
106 };
107 
108 // *************************************************************************
109 
110 SO_NODE_SOURCE(SoUnits);
111 
112 /*!
113   Constructor.
114 */
SoUnits(void)115 SoUnits::SoUnits(void)
116 {
117   SO_NODE_INTERNAL_CONSTRUCTOR(SoUnits);
118 
119   SO_NODE_ADD_FIELD(units, (SoUnits::METERS));
120 
121   SO_NODE_DEFINE_ENUM_VALUE(Units, METERS);
122   SO_NODE_DEFINE_ENUM_VALUE(Units, CENTIMETERS);
123   SO_NODE_DEFINE_ENUM_VALUE(Units, MILLIMETERS);
124   SO_NODE_DEFINE_ENUM_VALUE(Units, MICROMETERS);
125   SO_NODE_DEFINE_ENUM_VALUE(Units, MICRONS);
126   SO_NODE_DEFINE_ENUM_VALUE(Units, NANOMETERS);
127   SO_NODE_DEFINE_ENUM_VALUE(Units, ANGSTROMS);
128   SO_NODE_DEFINE_ENUM_VALUE(Units, KILOMETERS);
129   SO_NODE_DEFINE_ENUM_VALUE(Units, FEET);
130   SO_NODE_DEFINE_ENUM_VALUE(Units, INCHES);
131   SO_NODE_DEFINE_ENUM_VALUE(Units, POINTS);
132   SO_NODE_DEFINE_ENUM_VALUE(Units, YARDS);
133   SO_NODE_DEFINE_ENUM_VALUE(Units, MILES);
134   SO_NODE_DEFINE_ENUM_VALUE(Units, NAUTICAL_MILES);
135   SO_NODE_SET_SF_ENUM_TYPE(units, Units);
136 }
137 
138 /*!
139   Destructor.
140 */
~SoUnits()141 SoUnits::~SoUnits()
142 {
143 }
144 
145 // Doc from superclass.
146 void
initClass(void)147 SoUnits::initClass(void)
148 {
149   SO_NODE_INTERNAL_INIT_CLASS(SoUnits, SO_FROM_INVENTOR_1);
150 
151   SO_ENABLE(SoGetBoundingBoxAction, SoUnitsElement);
152   SO_ENABLE(SoGetMatrixAction, SoUnitsElement);
153   SO_ENABLE(SoGLRenderAction, SoUnitsElement);
154   SO_ENABLE(SoPickAction, SoUnitsElement);
155   SO_ENABLE(SoCallbackAction, SoUnitsElement);
156   SO_ENABLE(SoGetPrimitiveCountAction, SoUnitsElement);
157 }
158 
159 // Doc from superclass.
160 void
getBoundingBox(SoGetBoundingBoxAction * action)161 SoUnits::getBoundingBox(SoGetBoundingBoxAction * action)
162 {
163   SoUnits::doAction((SoAction*)action);
164 }
165 
166 // Doc from superclass.
167 void
GLRender(SoGLRenderAction * action)168 SoUnits::GLRender(SoGLRenderAction * action)
169 {
170   SoUnits::doAction((SoAction*)action);
171 }
172 
173 // Doc from superclass.
174 void
doAction(SoAction * action)175 SoUnits::doAction(SoAction * action)
176 {
177   if (this->units.isIgnored()) return;
178   SoState * state = action->getState();
179 
180   SoUnitsElement::Units currentunit = SoUnitsElement::get(state);
181 
182   if (currentunit != (SoUnitsElement::Units)units.getValue()) {
183     SoUnitsElement::set(state,
184                         (SoUnitsElement::Units)units.getValue());
185 
186     float scale = factors[units.getValue()] / factors[currentunit];
187     SoModelMatrixElement::scaleBy(state, this,
188                                   SbVec3f(scale, scale, scale));
189   }
190 }
191 
192 // Doc from superclass.
193 void
callback(SoCallbackAction * action)194 SoUnits::callback(SoCallbackAction * action)
195 {
196   SoUnits::doAction((SoAction *)action);
197 }
198 
199 // Doc from superclass.
200 void
getMatrix(SoGetMatrixAction * action)201 SoUnits::getMatrix(SoGetMatrixAction * action)
202 {
203   if (this->units.isIgnored()) return;
204 
205   SoState * state = action->getState();
206   SoUnitsElement::Units currentunit = SoUnitsElement::get(state);
207   if (currentunit != (SoUnitsElement::Units) this->units.getValue()) {
208     SoUnitsElement::set(state,
209                         (SoUnitsElement::Units)units.getValue());
210 
211     float scale = factors[(int)this->units.getValue()] / factors[(int) currentunit];
212     float inv = 1.0f / scale;
213 
214     SbMatrix m;
215     m.setScale(SbVec3f(scale, scale, scale));
216     action->getMatrix().multLeft(m);
217     m.setScale(SbVec3f(inv, inv, inv));
218     action->getInverse().multRight(m);
219   }
220 }
221 
222 // Doc from superclass.
223 void
pick(SoPickAction * action)224 SoUnits::pick(SoPickAction * action)
225 {
226   SoUnits::doAction((SoAction *)action);
227 }
228 
229 // Doc from superclass.
230 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)231 SoUnits::getPrimitiveCount(SoGetPrimitiveCountAction * action)
232 {
233   SoUnits::doAction((SoAction *)action);
234 }
235