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 SoScale2UniformDragger SoScale2UniformDragger.h Inventor/draggers/SoScale2UniformDragger.h
41   \brief The SoScale2UniformDragger class provides a mechanism for the end-user to scale in two dimensions.
42 
43   \ingroup draggers
44 
45   \DRAGGER_DEFAULT_SCREENSHOT
46 
47   <center>
48   \image html scale2uniform.png "Screen Shot of Default Dragger"
49   </center>
50 
51   Use this dragger to allow the end-user of your application to scale
52   along the X-axis and the Y-axis. (Use a transformation node in front
53   of the dragger to position it and re-orient it to scale in any
54   plane.)
55 
56   Scaling with this dragger can only be done in a uniform manner, ie
57   the X component of the SoScale2UniformDragger::scaleFactor will
58   always equal the Y component.
59 
60   For non-uniform scaling operations in 2 dimensions, use the
61   SoScale2Dragger.
62 
63   \sa SoScaleUniformDragger
64 */
65 
66 #include <Inventor/draggers/SoScale2UniformDragger.h>
67 
68 #include <cstring>
69 
70 #include <Inventor/nodes/SoSeparator.h>
71 #include <Inventor/nodes/SoSwitch.h>
72 
73 #include <Inventor/SbRotation.h>
74 #include <Inventor/projectors/SbLineProjector.h>
75 #include <Inventor/sensors/SoFieldSensor.h>
76 
77 #include <data/draggerDefaults/scale2UniformDragger.h>
78 
79 #include "nodekits/SoSubKitP.h"
80 
81 /*!
82   \var SoSFVec3f SoScale2UniformDragger::scaleFactor
83 
84   Continuously updated to contain the current vector of scaling along
85   the X, Y and Z axes.
86 
87   For the SoScale2UniformDragger, only the X and Y components are
88   used, the Z component will always be equal to 1 (ie no scaling).
89 */
90 
91 /*!
92   \var SoFieldSensor * SoScale2UniformDragger::fieldSensor
93   \COININTERNAL
94 */
95 /*!
96   \var SbLineProjector * SoScale2UniformDragger::lineProj
97   \COININTERNAL
98 */
99 
100 #define THISP(d) static_cast<SoScale2UniformDragger *>(d)
101 
102 class SoScale2UniformDraggerP {
103 public:
104 };
105 
106 SO_KIT_SOURCE(SoScale2UniformDragger);
107 
108 
109 // doc in superclass
110 void
initClass(void)111 SoScale2UniformDragger::initClass(void)
112 {
113   SO_KIT_INTERNAL_INIT_CLASS(SoScale2UniformDragger, SO_FROM_INVENTOR_1);
114 }
115 
116 // FIXME: document which parts need to be present in the geometry
117 // scenegraph, and what role they play in the dragger. 20010913 mortene.
118 /*!
119   \DRAGGER_CONSTRUCTOR
120 
121   \NODEKIT_PRE_DIAGRAM
122 
123   \verbatim
124   CLASS SoScale2UniformDragger
125   -->"this"
126         "callbackList"
127         "topSeparator"
128            "motionMatrix"
129            "geomSeparator"
130   -->         "scalerSwitch"
131   -->            "scaler"
132   -->            "scalerActive"
133   -->         "feedbackSwitch"
134   -->            "feedback"
135   -->            "feedbackActive"
136   \endverbatim
137 
138   \NODEKIT_POST_DIAGRAM
139 
140 
141   \NODEKIT_PRE_TABLE
142 
143   \verbatim
144   CLASS SoScale2UniformDragger
145   PVT   "this",  SoScale2UniformDragger  ---
146         "callbackList",  SoNodeKitListPart [ SoCallback, SoEventCallback ]
147   PVT   "topSeparator",  SoSeparator  ---
148   PVT   "motionMatrix",  SoMatrixTransform  ---
149   PVT   "geomSeparator",  SoSeparator  ---
150   PVT   "scalerSwitch",  SoSwitch  ---
151         "scaler",  SoSeparator  ---
152         "scalerActive",  SoSeparator  ---
153   PVT   "feedbackSwitch",  SoSwitch  ---
154         "feedback",  SoSeparator  ---
155         "feedbackActive",  SoSeparator  ---
156   \endverbatim
157 
158   \NODEKIT_POST_TABLE
159 */
SoScale2UniformDragger(void)160 SoScale2UniformDragger::SoScale2UniformDragger(void)
161 {
162   SO_KIT_INTERNAL_CONSTRUCTOR(SoScale2UniformDragger);
163 
164   SO_KIT_ADD_CATALOG_ENTRY(scalerSwitch, SoSwitch, TRUE, geomSeparator, feedbackSwitch, FALSE);
165   SO_KIT_ADD_CATALOG_ENTRY(scaler, SoSeparator, TRUE, scalerSwitch, scalerActive, TRUE);
166   SO_KIT_ADD_CATALOG_ENTRY(scalerActive, SoSeparator, TRUE, scalerSwitch, "", TRUE);
167   SO_KIT_ADD_CATALOG_ENTRY(feedbackSwitch, SoSwitch, TRUE, geomSeparator, "", FALSE);
168   SO_KIT_ADD_CATALOG_ENTRY(feedback, SoSeparator, TRUE, feedbackSwitch, feedbackActive, TRUE);
169   SO_KIT_ADD_CATALOG_ENTRY(feedbackActive, SoSeparator, TRUE, feedbackSwitch, "", TRUE);
170 
171   if (SO_KIT_IS_FIRST_INSTANCE()) {
172     SoInteractionKit::readDefaultParts("scale2UniformDragger.iv",
173                                        SCALE2UNIFORMDRAGGER_draggergeometry,
174                                        static_cast<int>(strlen(SCALE2UNIFORMDRAGGER_draggergeometry)));
175   }
176 
177   SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
178   SO_KIT_INIT_INSTANCE();
179 
180   // initialize default parts
181   this->setPartAsDefault("scaler", "scale2UniformScaler");
182   this->setPartAsDefault("scalerActive", "scale2UniformScalerActive");
183   this->setPartAsDefault("feedback", "scale2UniformFeedback");
184   this->setPartAsDefault("feedbackActive", "scale2UniformFeedbackActive");
185 
186   // initialize swich values
187   SoSwitch *sw;
188   sw = SO_GET_ANY_PART(this, "scalerSwitch", SoSwitch);
189   SoInteractionKit::setSwitchValue(sw, 0);
190   sw = SO_GET_ANY_PART(this, "feedbackSwitch", SoSwitch);
191   SoInteractionKit::setSwitchValue(sw, 0);
192 
193   // setup projector
194   this->lineProj = new SbLineProjector();
195 
196   this->addStartCallback(SoScale2UniformDragger::startCB);
197   this->addMotionCallback(SoScale2UniformDragger::motionCB);
198   this->addFinishCallback(SoScale2UniformDragger::finishCB);
199 
200   this->addValueChangedCallback(SoScale2UniformDragger::valueChangedCB);
201 
202   this->fieldSensor = new SoFieldSensor(SoScale2UniformDragger::fieldSensorCB, this);
203   this->fieldSensor->setPriority(0);
204 
205   this->setUpConnections(TRUE, TRUE);
206 }
207 
208 /*!
209   Protected destructor.
210 
211   (Dragger classes are derived from SoBase, so they are reference
212   counted and automatically destroyed when their reference count goes
213   to 0.)
214  */
~SoScale2UniformDragger()215 SoScale2UniformDragger::~SoScale2UniformDragger()
216 {
217   delete this->lineProj;
218   delete this->fieldSensor;
219 }
220 
221 // Doc in superclass.
222 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)223 SoScale2UniformDragger::setUpConnections(SbBool onoff, SbBool doitalways)
224 {
225   if (!doitalways && this->connectionsSetUp == onoff) return onoff;
226 
227   SbBool oldval = this->connectionsSetUp;
228 
229   if (onoff) {
230     inherited::setUpConnections(onoff, doitalways);
231 
232     SoScale2UniformDragger::fieldSensorCB(this, NULL);
233 
234     if (this->fieldSensor->getAttachedField() != &this->scaleFactor) {
235       this->fieldSensor->attach(&this->scaleFactor);
236     }
237   }
238   else {
239     if (this->fieldSensor->getAttachedField() != NULL) {
240       this->fieldSensor->detach();
241     }
242     inherited::setUpConnections(onoff, doitalways);
243   }
244   this->connectionsSetUp = onoff;
245   return oldval;
246 }
247 
248 /*! \COININTERNAL */
249 void
fieldSensorCB(void * d,SoSensor *)250 SoScale2UniformDragger::fieldSensorCB(void * d, SoSensor *)
251 {
252   assert(d);
253   SoScale2UniformDragger * thisp = THISP(d);
254   SbMatrix matrix = thisp->getMotionMatrix();
255 
256   SbVec3f t, s;
257   SbRotation r, so;
258 
259   matrix.getTransform(t, r, s, so);
260   s = thisp->scaleFactor.getValue();
261   matrix.setTransform(t, r, s, so);
262   thisp->setMotionMatrix(matrix);
263 }
264 
265 /*! \COININTERNAL */
266 void
valueChangedCB(void *,SoDragger * d)267 SoScale2UniformDragger::valueChangedCB(void *, SoDragger * d)
268 {
269   SoScale2UniformDragger * thisp = THISP(d);
270   SbMatrix matrix = thisp->getMotionMatrix();
271 
272   SbVec3f trans, scale;
273   SbRotation rot, scaleOrient;
274   matrix.getTransform(trans, rot, scale, scaleOrient);
275   thisp->fieldSensor->detach();
276   if (thisp->scaleFactor.getValue() != scale)
277     thisp->scaleFactor = scale;
278   thisp->fieldSensor->attach(&thisp->scaleFactor);
279 }
280 
281 /*! \COININTERNAL */
282 void
startCB(void *,SoDragger * d)283 SoScale2UniformDragger::startCB(void *, SoDragger * d)
284 {
285   SoScale2UniformDragger * thisp = THISP(d);
286   thisp->dragStart();
287 }
288 
289 /*! \COININTERNAL */
290 void
motionCB(void *,SoDragger * d)291 SoScale2UniformDragger::motionCB(void *, SoDragger * d)
292 {
293   SoScale2UniformDragger * thisp = THISP(d);
294   thisp->drag();
295 }
296 
297 /*! \COININTERNAL */
298 void
finishCB(void *,SoDragger * d)299 SoScale2UniformDragger::finishCB(void *, SoDragger * d)
300 {
301   SoScale2UniformDragger * thisp = THISP(d);
302   thisp->dragFinish();
303 }
304 
305 /*! \COININTERNAL
306   Called when dragger is selected (picked) by the user.
307 */
308 void
dragStart(void)309 SoScale2UniformDragger::dragStart(void)
310 {
311   SoSwitch *sw;
312   sw = SO_GET_ANY_PART(this, "scalerSwitch", SoSwitch);
313   SoInteractionKit::setSwitchValue(sw, 1);
314   sw = SO_GET_ANY_PART(this, "feedbackSwitch", SoSwitch);
315   SoInteractionKit::setSwitchValue(sw, 1);
316 
317   SbVec3f startPt = this->getLocalStartingPoint();
318   startPt[2] = 0.0f;
319   this->lineProj->setLine(SbLine(SbVec3f(0.0f, 0.0f, 0.0f), startPt));
320 }
321 
322 /*! \COININTERNAL
323   Called when user drags the mouse after picking the dragger.
324 */
325 void
drag(void)326 SoScale2UniformDragger::drag(void)
327 {
328   this->lineProj->setViewVolume(this->getViewVolume());
329   this->lineProj->setWorkingSpace(this->getLocalToWorldMatrix());
330   SbVec3f startPt = this->getLocalStartingPoint();
331   SbVec3f projPt = lineProj->project(this->getNormalizedLocaterPosition());
332   startPt[2] = 0.0f;
333   projPt[2] = 0.0f;
334 
335   float orglen = startPt.length();
336   float currlen = projPt.length();
337 
338   float scale = 0.0f;
339   if (orglen > 0.0f) scale = currlen / orglen;
340 
341   if (scale > 0.0f && startPt.dot(projPt) < 0.0f) scale = 0.0f;
342 
343   this->setMotionMatrix(this->appendScale(this->getStartMotionMatrix(),
344                                           SbVec3f(scale, scale, 1.0f),
345                                           SbVec3f(0.0f, 0.0f, 0.0f)));
346 }
347 
348 /*! \COININTERNAL
349   Called when mouse button is released after picking and interacting
350   with the dragger.
351 */
352 void
dragFinish(void)353 SoScale2UniformDragger::dragFinish(void)
354 {
355   SoSwitch *sw;
356   sw = SO_GET_ANY_PART(this, "scalerSwitch", SoSwitch);
357   SoInteractionKit::setSwitchValue(sw, 0);
358   sw = SO_GET_ANY_PART(this, "feedbackSwitch", SoSwitch);
359   SoInteractionKit::setSwitchValue(sw, 0);
360 }
361 
362 #undef THISP
363 #endif // HAVE_DRAGGERS
364