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_DRAGGERS
38
39 /*!
40 \class SoJackDragger SoJackDragger.h Inventor/draggers/SoJackDragger.h
41 \brief The SoJackDragger class is a dragger you can translate, rotate and scale.
42
43 \ingroup draggers
44
45 \DRAGGER_DEFAULT_SCREENSHOT
46
47 <center>
48 \image html jack.png "Screen Shot of Default Dragger"
49 </center>
50
51 Translation is done with this dragger by picking the flat
52 transparent box ("x-z" translation) or the solid middle part of the
53 axis ("y"-axis translation). Press a SHIFT-key while translating in
54 x-z to constrain to one of the principal axes.
55
56 Uniform scale operations can be done by dragging any of the 6
57 cubes. Non-uniform scale operations can not be done with this
58 dragger.
59
60 Rotations are invoked by clicking and dragging the line parts of the
61 3 principal "axes" of the dragger geometry.
62
63 <b>NB:</b> How to rotate the dragger might be abit unintuitive for
64 the end user. If the dragger is to be used 'out of the box', a good
65 documentation should be added to your application. An alternative is
66 to modify the geometry to increase the affordance of the dragger.
67 See the SoDragger documentation on how to change the geometry of a
68 dragger.
69
70 An "action shot" of the SoJackDragger used within an SoClipPlaneManip:
71 <center>
72 \image html jack-in-action.png "Action Shot of Jack Dragger in a Clip Plane Manipulator"
73 </center>
74
75 The name "Jack dragger" probably stems from this dragger being
76 implemented by SGI for interacting with a "jack-in-the-box" type
77 model way back in the Inventor history.
78
79 For programmer convenience, this dragger comes fully wrapped within
80 instances of the SoJackManip class. The SoClipPlaneManip manipulator
81 also uses this dragger, for controlling an SoClipPlane node.
82 */
83
84 #include <Inventor/draggers/SoJackDragger.h>
85
86 #include <cstring>
87
88 #include <Inventor/draggers/SoDragPointDragger.h>
89 #include <Inventor/draggers/SoRotateSphericalDragger.h>
90 #include <Inventor/draggers/SoScaleUniformDragger.h>
91 #include <Inventor/nodes/SoAntiSquish.h>
92 #include <Inventor/nodes/SoSurroundScale.h>
93 #include <Inventor/sensors/SoFieldSensor.h>
94
95 #include <data/draggerDefaults/jackDragger.h>
96
97 #include "nodekits/SoSubKitP.h"
98 #include "SbBasicP.h"
99 #include "coindefs.h"
100
101 /*!
102 \var SoSFVec3f SoJackDragger::translation
103
104 Continuously updated to contain the current translation from the
105 dragger's local origo position.
106
107 The application programmer applying this dragger in his code should
108 connect the relevant node fields in the scene to this field to make
109 it follow the dragger.
110 */
111
112 /*!
113 \var SoSFRotation SoJackDragger::rotation
114
115 This field is continuously updated to contain the rotation of the
116 current direction vector of the dragger.
117 */
118
119 /*!
120 \var SoSFVec3f SoJackDragger::scaleFactor
121
122 Continuously updated to contain the current vector of scaling along
123 the X, Y and Z axes.
124
125 Only uniform scaling can be done with the SoJackDragger, so the 3
126 vector components will always be equal.
127 */
128
129
130 /*!
131 \var SoFieldSensor * SoJackDragger::translFieldSensor
132 \COININTERNAL
133 */
134 /*!
135 \var SoFieldSensor * SoJackDragger::rotFieldSensor
136 \COININTERNAL
137 */
138 /*!
139 \var SoFieldSensor * SoJackDragger::scaleFieldSensor
140 \COININTERNAL
141 */
142
143 class SoJackDraggerP {
144 public:
145 };
146
147 SO_KIT_SOURCE(SoJackDragger);
148
149
150 // doc in superclass
151 void
initClass(void)152 SoJackDragger::initClass(void)
153 {
154 SO_KIT_INTERNAL_INIT_CLASS(SoJackDragger, SO_FROM_INVENTOR_1);
155 }
156
157 // FIXME: document which parts need to be present in the geometry
158 // scenegraph, and what role they play in the dragger. 20010913 mortene.
159 /*!
160 \DRAGGER_CONSTRUCTOR
161
162 \NODEKIT_PRE_DIAGRAM
163
164 \verbatim
165 CLASS SoJackDragger
166 -->"this"
167 "callbackList"
168 "topSeparator"
169 "motionMatrix"
170 --> "surroundScale"
171 --> "antiSquish"
172 --> "scaler"
173 --> "rotator"
174 --> "translator"
175 "geomSeparator"
176 \endverbatim
177
178 \NODEKIT_POST_DIAGRAM
179
180
181 \NODEKIT_PRE_TABLE
182
183 \verbatim
184 CLASS SoJackDragger
185 PVT "this", SoJackDragger ---
186 "callbackList", SoNodeKitListPart [ SoCallback, SoEventCallback ]
187 PVT "topSeparator", SoSeparator ---
188 PVT "motionMatrix", SoMatrixTransform ---
189 "surroundScale", SoSurroundScale ---
190 "antiSquish", SoAntiSquish ---
191 "scaler", SoScaleUniformDragger ---
192 "rotator", SoRotateSphericalDragger ---
193 "translator", SoDragPointDragger ---
194 PVT "geomSeparator", SoSeparator ---
195 \endverbatim
196
197 \NODEKIT_POST_TABLE
198 */
SoJackDragger(void)199 SoJackDragger::SoJackDragger(void)
200 {
201 SO_KIT_INTERNAL_CONSTRUCTOR(SoJackDragger);
202
203 SO_KIT_ADD_CATALOG_ENTRY(surroundScale, SoSurroundScale, TRUE, topSeparator, antiSquish, TRUE);
204 SO_KIT_ADD_CATALOG_ENTRY(antiSquish, SoAntiSquish, FALSE, topSeparator, scaler, TRUE);
205 SO_KIT_ADD_CATALOG_ENTRY(scaler, SoScaleUniformDragger, TRUE, topSeparator, rotator, TRUE);
206 SO_KIT_ADD_CATALOG_ENTRY(rotator, SoRotateSphericalDragger, TRUE, topSeparator, translator, TRUE);
207 SO_KIT_ADD_CATALOG_ENTRY(translator, SoDragPointDragger, TRUE, topSeparator, geomSeparator, TRUE);
208
209
210 if (SO_KIT_IS_FIRST_INSTANCE()) {
211 SoInteractionKit::readDefaultParts("jackDragger.iv",
212 JACKDRAGGER_draggergeometry,
213 static_cast<int>(strlen(JACKDRAGGER_draggergeometry)));
214 }
215
216 SO_KIT_ADD_FIELD(rotation, (SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f)));
217 SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
218 SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
219
220 SO_KIT_INIT_INSTANCE();
221
222 SO_GET_ANY_PART(this, "translator", SoDragPointDragger);
223 SO_GET_ANY_PART(this, "rotator", SoRotateSphericalDragger);
224 SO_GET_ANY_PART(this, "scaler", SoScaleUniformDragger);
225
226 SoAntiSquish *squish = SO_GET_ANY_PART(this, "antiSquish", SoAntiSquish);
227 squish->sizing = SoAntiSquish::BIGGEST_DIMENSION;
228 // if the antisquish node to recalculate its parameters on every
229 // traversal, rotating this dragger destroys its geometry
230 squish->recalcAlways = FALSE;
231
232 this->addValueChangedCallback(SoJackDragger::valueChangedCB);
233 this->rotFieldSensor = new SoFieldSensor(SoJackDragger::fieldSensorCB, this);
234 this->rotFieldSensor->setPriority(0);
235 this->translFieldSensor = new SoFieldSensor(SoJackDragger::fieldSensorCB, this);
236 this->translFieldSensor->setPriority(0);
237 this->scaleFieldSensor = new SoFieldSensor(SoJackDragger::fieldSensorCB, this);
238 this->scaleFieldSensor->setPriority(0);
239 this->setUpConnections(TRUE, TRUE);
240 }
241
242 /*!
243 Protected destructor.
244
245 (Dragger classes are derived from SoBase, so they are reference
246 counted and automatically destroyed when their reference count goes
247 to 0.)
248 */
~SoJackDragger()249 SoJackDragger::~SoJackDragger()
250 {
251 delete this->rotFieldSensor;
252 delete this->scaleFieldSensor;
253 delete this->translFieldSensor;
254 }
255
256 // Doc in superclass.
257 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)258 SoJackDragger::setUpConnections(SbBool onoff, SbBool doitalways)
259 {
260 if (!doitalways && this->connectionsSetUp == onoff) return onoff;
261
262 if (onoff) {
263 inherited::setUpConnections(onoff, doitalways);
264 SoDragger *child;
265 child = coin_assert_cast<SoDragger *>(this->getAnyPart("rotator", FALSE));
266 child->setPartAsDefault("rotator",
267 "jackRotatorRotator");
268 child->setPartAsDefault("rotatorActive",
269 "jackRotatorRotatorActive");
270 child->setPartAsDefault("feedback",
271 "jackRotatorFeedback");
272 this->addChildDragger(child);
273
274 child = coin_assert_cast<SoDragger *>(this->getAnyPart("scaler", FALSE));
275 child->setPartAsDefault("scaler", "jackScalerScaler");
276 child->setPartAsDefault("scalerActive", "jackScalerScalerActive");
277 child->setPartAsDefault("feedback", "jackScalerFeedback");
278 child->setPartAsDefault("feedbackActive", "jackScalerFeedbackActive");
279 this->addChildDragger(child);
280
281 child = coin_assert_cast<SoDragger *>(this->getAnyPart("translator", FALSE));
282 child->setPartAsDefault("xTranslator.translator", "jackTranslatorLineTranslator");
283 child->setPartAsDefault("yTranslator.translator", "jackTranslatorLineTranslator");
284 child->setPartAsDefault("zTranslator.translator", "jackTranslatorLineTranslator");
285 child->setPartAsDefault("xTranslator.translatorActive", "jackTranslatorLineTranslatorActive");
286 child->setPartAsDefault("yTranslator.translatorActive", "jackTranslatorLineTranslatorActive");
287 child->setPartAsDefault("zTranslator.translatorActive", "jackTranslatorLineTranslatorActive");
288 child->setPartAsDefault("xzTranslator.translator", "jackTranslatorPlaneTranslator");
289 child->setPartAsDefault("xyTranslator.translator", "jackTranslatorPlaneTranslator");
290 child->setPartAsDefault("yzTranslator.translator", "jackTranslatorPlaneTranslator");
291 child->setPartAsDefault("xzTranslator.translatorActive", "jackTranslatorPlaneTranslatorActive");
292 child->setPartAsDefault("xyTranslator.translatorActive", "jackTranslatorPlaneTranslatorActive");
293 child->setPartAsDefault("yzTranslator.translatorActive", "jackTranslatorPlaneTranslatorActive");
294 child->setPartAsDefault("xFeedback", "jackTranslatorXFeedback");
295 child->setPartAsDefault("yFeedback", "jackTranslatorYFeedback");
296 child->setPartAsDefault("zFeedback", "jackTranslatorZFeedback");
297 child->setPartAsDefault("xzFeedback", "jackTranslatorXZFeedback");
298 child->setPartAsDefault("xyFeedback", "jackTranslatorXYFeedback");
299 child->setPartAsDefault("yzFeedback", "jackTranslatorYZFeedback");
300 this->addChildDragger(child);
301
302 if (this->rotFieldSensor->getAttachedField() != &this->rotation) {
303 this->rotFieldSensor->attach(&this->rotation);
304 }
305 if (this->scaleFieldSensor->getAttachedField() != &this->scaleFactor) {
306 this->scaleFieldSensor->attach(&this->scaleFactor);
307 }
308 if (this->translFieldSensor->getAttachedField() != &this->translation) {
309 this->translFieldSensor->attach(&this->translation);
310 }
311 }
312 else {
313 this->removeChildDragger("rotator");
314 this->removeChildDragger("scaler");
315 this->removeChildDragger("translator");
316 if (this->rotFieldSensor->getAttachedField() != NULL) {
317 this->rotFieldSensor->detach();
318 }
319 if (this->translFieldSensor->getAttachedField() != NULL) {
320 this->translFieldSensor->detach();
321 }
322 if (this->scaleFieldSensor->getAttachedField() != NULL) {
323 this->scaleFieldSensor->detach();
324 }
325 inherited::setUpConnections(onoff, doitalways);
326 }
327 return !(this->connectionsSetUp = onoff);
328 }
329
330 // Doc in superclass.
331 void
setDefaultOnNonWritingFields(void)332 SoJackDragger::setDefaultOnNonWritingFields(void)
333 {
334 this->translator.setDefault(TRUE);
335 this->rotator.setDefault(TRUE);
336 this->scaler.setDefault(TRUE);
337
338 this->antiSquish.setDefault(TRUE);
339 this->surroundScale.setDefault(TRUE);
340
341 inherited::setDefaultOnNonWritingFields();
342 }
343
344 /*! \COININTERNAL */
345 void
fieldSensorCB(void * d,SoSensor *)346 SoJackDragger::fieldSensorCB(void * d, SoSensor *)
347 {
348 SoJackDragger * thisp = static_cast<SoJackDragger *>(d);
349 SbMatrix matrix = thisp->getMotionMatrix();
350 thisp->workFieldsIntoTransform(matrix);
351 thisp->setMotionMatrix(matrix);
352 }
353
354 /*! \COININTERNAL */
355 void
valueChangedCB(void *,SoDragger * d)356 SoJackDragger::valueChangedCB(void *, SoDragger * d)
357 {
358 SoJackDragger * thisp = static_cast<SoJackDragger *>(d);
359 SbMatrix matrix = thisp->getMotionMatrix();
360
361 SbVec3f trans, scale;
362 SbRotation rot, scaleOrient;
363 matrix.getTransform(trans, rot, scale, scaleOrient);
364
365 thisp->translFieldSensor->detach();
366 if (thisp->translation.getValue() != trans)
367 thisp->translation = trans;
368 thisp->translFieldSensor->attach(&thisp->translation);
369
370 thisp->rotFieldSensor->detach();
371 if (thisp->rotation.getValue() != rot)
372 thisp->rotation = rot;
373 thisp->rotFieldSensor->attach(&thisp->rotation);
374
375 thisp->scaleFieldSensor->detach();
376 if (thisp->scaleFactor.getValue() != scale)
377 thisp->scaleFactor = scale;
378 thisp->scaleFieldSensor->attach(&thisp->scaleFactor);
379 }
380
381 /*!
382 Used to invalidate the \e surroundScale and \e antiSquish parts when
383 a child dragger starts or finishes dragging.
384 */
385 void
invalidateSurroundScaleCB(void * f,SoDragger * COIN_UNUSED_ARG (d))386 SoJackDragger::invalidateSurroundScaleCB(void * f, SoDragger * COIN_UNUSED_ARG(d))
387 {
388 SoJackDragger * thisp = static_cast<SoJackDragger *>(f);
389 SoSurroundScale * surround = SO_CHECK_PART(thisp, "surroundScale", SoSurroundScale);
390 if (surround) surround->invalidate();
391 SoAntiSquish *squish = SO_CHECK_PART(thisp, "antiSquish", SoAntiSquish);
392 if (squish) squish->recalc();
393 }
394
395 //
396 // convenience method that takes care of callbacks before registering child
397 //
398 void
addChildDragger(SoDragger * child)399 SoJackDragger::addChildDragger(SoDragger *child)
400 {
401 child->addStartCallback(SoJackDragger::invalidateSurroundScaleCB, this);
402 child->addFinishCallback(SoJackDragger::invalidateSurroundScaleCB, this);
403 this->registerChildDragger(child);
404 }
405
406 //
407 // convenience method that removes callbacks before unregistering child
408 //
409 void
removeChildDragger(const char * childname)410 SoJackDragger::removeChildDragger(const char *childname)
411 {
412 SoDragger * child = coin_assert_cast<SoDragger *>(this->getAnyPart(childname, FALSE));
413 child->removeStartCallback(SoJackDragger::invalidateSurroundScaleCB, this);
414 child->removeFinishCallback(SoJackDragger::invalidateSurroundScaleCB, this);
415 this->unregisterChildDragger(child);
416 }
417
418 #endif // HAVE_DRAGGERS
419