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 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36
37 #ifdef HAVE_VRML97
38
39 /*!
40 \class SoVRMLProximitySensor SoVRMLProximitySensor.h Inventor/VRMLnodes/SoVRMLProximitySensor.h
41 \brief The SoVRMLProximitySensor class is used to generate events when the viewer enters or exits a region.
42
43 \ingroup VRMLnodes
44
45 \WEB3DCOPYRIGHT
46
47 \verbatim
48 ProximitySensor {
49 exposedField SFVec3f center 0 0 0 # (-,)
50 exposedField SFVec3f size 0 0 0 # [0,)
51 exposedField SFBool enabled TRUE
52 eventOut SFBool isActive
53 eventOut SFVec3f position_changed
54 eventOut SFRotation orientation_changed
55 eventOut SFTime enterTime
56 eventOut SFTime exitTime
57 }
58 \endverbatim
59
60 The ProximitySensor node generates events when the viewer enters,
61 exits, and moves within a region in space (defined by a box).
62
63 A proximity sensor is enabled or disabled by sending it an enabled
64 event with a value of TRUE or FALSE. A disabled sensor does not send
65 events.
66
67 A ProximitySensor node generates isActive TRUE/FALSE events as the
68 viewer enters and exits the rectangular box defined by its center
69 and size fields. Browsers shall interpolate viewer positions and
70 timestamp the isActive events with the exact time the viewer first
71 intersected the proximity region.
72
73 The \e center field defines the centre point of the proximity region
74 in object space. The \e size field specifies a vector which defines
75 the width (x), height (y), and depth (z) of the box bounding the
76 region. The components of the size field shall be greater than or
77 equal to zero. ProximitySensor nodes are affected by the
78 hierarchical transformations of their parents.
79
80 The \e enterTime event is generated whenever the isActive TRUE event
81 is generated (user enters the box), and \e exitTime events are
82 generated whenever an isActive FALSE event is generated (user exits
83 the box).
84
85 The \e position_changed and \e orientation_changed eventOuts send
86 events whenever the user is contained within the proximity region
87 and the position and orientation of the viewer changes with respect
88 to the ProximitySensor node's coordinate system including enter and
89 exit times.
90
91 The viewer movement may be a result of a variety of circumstances
92 resulting from browser navigation, ProximitySensor node's coordinate
93 system changes, or bound Viewpoint node's position or orientation
94 changes.
95
96 Each ProximitySensor node behaves independently of all other
97 ProximitySensor nodes. Every enabled ProximitySensor node that is
98 affected by the viewer's movement receives and sends events,
99 possibly resulting in multiple
100
101 ProximitySensor nodes receiving and sending events
102 simultaneously. Unlike TouchSensor nodes, there is no notion of a
103 ProximitySensor node lower in the scene graph "grabbing" events.
104
105 Instanced (DEF/USE) ProximitySensor nodes use the union of all the
106 boxes to check for enter and exit. A multiply instanced
107 ProximitySensor node will detect enter and exit for all instances of
108 the box and send enter/exit events appropriately. However, the
109 results are undefined if the any of the boxes of a multiply
110 instanced ProximitySensor node overlap.
111
112 A ProximitySensor node that surrounds the entire world has an
113 enterTime equal to the time that the world was entered and can be
114 used to start up animations or behaviours as soon as a world is
115 loaded.
116
117 A ProximitySensor node with a box containing zero volume (i.e., any
118 size field element of 0.0) cannot generate events. This is
119 equivalent to setting the enabled field to FALSE.
120
121 A ProximitySensor read from a VRML file shall generate isActive
122 TRUE, position_changed, orientation_changed and enterTime events if
123 the sensor is enabled and the viewer is inside the proximity region.
124
125 A ProximitySensor inserted into the transformation hierarchy shall
126 generate isActive TRUE, position_changed, orientation_changed and
127 enterTime events if the sensor is enabled and the viewer is inside
128 the proximity region.
129
130 A ProximitySensor removed from the transformation hierarchy shall
131 generate isActive FALSE, position_changed, orientation_changed and
132 exitTime events if the sensor is enabled and the viewer is inside
133 the proximity region.
134
135 */
136
137 /*!
138 \var SoSFVec3f SoVRMLProximitySensor::center
139 The center of the region. Default value is (0,0,0).
140 */
141
142 /*!
143 \var SoSFVec3f SoVRMLProximitySensor::size
144 The region size. Default value is (0, 0, 0).
145 */
146
147 /*!
148 \var SoSFBool SoVRMLProximitySensor::enabled
149 Enable/disable sensor. Default value is TRUE.
150 */
151
152
153 /*!
154 \var SoSFBool SoVRMLProximitySensor::isActive
155 An eventOut that is sent every time the sensor changes state.
156 */
157
158 /*!
159 \var SoSFVec3f SoVRMLProximitySensor::position_changed
160
161 An eventOut that is sent when the viewer is inside the region and
162 the viewer position or orientation is changed.
163
164 */
165
166 /*!
167 \var SoSFRotation SoVRMLProximitySensor::orientation_changed
168
169 An eventOut that is sent when the viewer is inside the region and
170 the viewer position or orientation is changed.
171
172 */
173
174 /*!
175 \var SoSFTime SoVRMLProximitySensor::enterTime
176 An eventOut that is sent when the viewer enters the region.
177 */
178
179 /*!
180 \var SoSFTime SoVRMLProximitySensor::exitTime
181 An eventOut that is sent when the viewer exits the region.
182 */
183
184 #include <Inventor/VRMLnodes/SoVRMLProximitySensor.h>
185 #include "coindefs.h"
186
187 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
188 #include <Inventor/actions/SoAction.h>
189 #include <Inventor/elements/SoViewVolumeElement.h>
190 #include <Inventor/elements/SoViewingMatrixElement.h>
191 #include <Inventor/elements/SoModelMatrixElement.h>
192 #include <Inventor/SoDB.h>
193 #include <Inventor/SbBox3f.h>
194 #include <Inventor/misc/SoState.h>
195
196 #include "nodes/SoSubNodeP.h"
197
198 SO_NODE_SOURCE(SoVRMLProximitySensor);
199
200 //
201 // returns the current time. First tries the realTime field, then
202 // SbTime::getTimeOfDay() if field is not found.
203 //
204 static SbTime
prox_get_current_time(void)205 prox_get_current_time(void)
206 {
207 SoField * realtime = SoDB::getGlobalField("realTime");
208 if (realtime && realtime->isOfType(SoSFTime::getClassTypeId())) {
209 return ((SoSFTime*)realtime)->getValue();
210 }
211 return SbTime::getTimeOfDay();
212 }
213
214 // Doc in parent
215 void
initClass(void)216 SoVRMLProximitySensor::initClass(void)
217 {
218 SO_NODE_INTERNAL_INIT_CLASS(SoVRMLProximitySensor, SO_VRML97_NODE_TYPE);
219 }
220
221 /*!
222 Constructor.
223 */
SoVRMLProximitySensor(void)224 SoVRMLProximitySensor::SoVRMLProximitySensor(void)
225 {
226 SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLProximitySensor);
227
228 SO_VRMLNODE_ADD_EXPOSED_FIELD(center, (0.0f, 0.0f, 0.0f));
229 SO_VRMLNODE_ADD_EXPOSED_FIELD(size, (0.0f, 0.0f, 0.0f));
230 SO_VRMLNODE_ADD_EXPOSED_FIELD(enabled, (TRUE));
231
232 SO_VRMLNODE_ADD_EVENT_OUT(isActive);
233 SO_VRMLNODE_ADD_EVENT_OUT(position_changed);
234 SO_VRMLNODE_ADD_EVENT_OUT(orientation_changed);
235 SO_VRMLNODE_ADD_EVENT_OUT(enterTime);
236 SO_VRMLNODE_ADD_EVENT_OUT(exitTime);
237
238 // initialize eventOut values that we might read
239 this->isActive = FALSE;
240 this->position_changed = SbVec3f(0.0f, 0.0f, 0.0f);
241 this->orientation_changed = SbRotation();
242 }
243
244 /*!
245 Destructor.
246 */
~SoVRMLProximitySensor()247 SoVRMLProximitySensor::~SoVRMLProximitySensor()
248 {
249 }
250
251 // Doc in parent
252 SbBool
affectsState(void) const253 SoVRMLProximitySensor::affectsState(void) const
254 {
255 return FALSE;
256 }
257
258 // Doc in parent
259 void
doAction(SoAction * action)260 SoVRMLProximitySensor::doAction(SoAction * action)
261 {
262 if (!this->enabled.getValue()) return;
263
264 SbBool wasactive = this->isActive.getValue();
265 SbVec3f s = this->size.getValue() * 0.5f;
266 SbTime currtime = prox_get_current_time();
267
268 if (s[0] <= 0.0f || s[1] <= 0.0f || s[2] <= 0.0f) {
269 if (wasactive) {
270 this->isActive = FALSE;
271 this->exitTime = currtime;
272 }
273 return;
274 }
275
276 SoState * state = action->getState();
277 const SbViewVolume & vv = SoViewVolumeElement::get(state);
278 const SbMatrix & mm = SoModelMatrixElement::get(state);
279 const SbMatrix & vm = SoViewingMatrixElement::get(state);
280
281 // FIXME: if it's not possible to invert the matrix, move proximity
282 // area to world space and do the testing there.
283
284 SbVec3f viewer = vv.getProjectionPoint(); // world space
285 mm.inverse().multVecMatrix(viewer, viewer); // object space
286
287 SbVec3f c = this->center.getValue();
288 SbBox3f box(c[0]-s[0], c[1]-s[1], c[2]-s[2],
289 c[0]+s[0], c[1]+s[1], c[2]+s[2]);
290 SbBool inside = box.intersect(viewer);
291
292 SbRotation oldrot = this->orientation_changed.getValue();
293 SbVec3f oldpos = this->position_changed.getValue();
294
295 if (inside) {
296 if (!wasactive) {
297 this->isActive = TRUE;
298 this->enterTime = currtime;
299 }
300 SbRotation newrot = SbRotation(vm).inverse();
301 if (!wasactive || newrot != oldrot) {
302 this->orientation_changed = newrot;
303 }
304 if (!wasactive || viewer != oldpos) {
305 this->position_changed = viewer;
306 }
307 }
308 else if (!inside && wasactive) {
309 this->isActive = FALSE;
310 this->exitTime = currtime;
311 }
312 }
313
314 // Doc in parent
315 void
GLRender(SoGLRenderAction * action)316 SoVRMLProximitySensor::GLRender(SoGLRenderAction * action)
317 {
318 SoVRMLProximitySensor::doAction((SoAction*) action);
319 }
320
321 // Doc in parent
322 void
callback(SoCallbackAction * COIN_UNUSED_ARG (action))323 SoVRMLProximitySensor::callback(SoCallbackAction * COIN_UNUSED_ARG(action))
324 {
325 }
326
327 // Doc in parent
328 void
rayPick(SoRayPickAction * COIN_UNUSED_ARG (action))329 SoVRMLProximitySensor::rayPick(SoRayPickAction * COIN_UNUSED_ARG(action))
330 {
331 }
332
333 // Doc in parent
334 void
getBoundingBox(SoGetBoundingBoxAction * COIN_UNUSED_ARG (action))335 SoVRMLProximitySensor::getBoundingBox(SoGetBoundingBoxAction * COIN_UNUSED_ARG(action))
336 {
337 }
338
339 // Doc in parent
340 void
notify(SoNotList * list)341 SoVRMLProximitySensor::notify(SoNotList * list)
342 {
343 inherited::notify(list);
344 }
345
346 #endif // HAVE_VRML97
347