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