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