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 SoTransformerDragger SoTransformerDragger.h Inventor/draggers/SoTransformerDragger.h
41 \brief The SoTransformerDragger provides geometry for translation, scaling and rotations.
42
43 \ingroup draggers
44
45 \DRAGGER_DEFAULT_SCREENSHOT
46
47 <center>
48 \image html transformer.png "Screen Shot of Default Dragger"
49 </center>
50
51 Translate the dragger by clicking and dragging any of the
52 (invisible) sides. Translation will default be done in the plane of
53 the side the end-user selected. The user can hold down a \c SHIFT
54 key to lock translation to a single of the axes in the plane. By
55 holding down a \c CTRL key instead, translation can be done along
56 the plane's normal vector.
57
58 Scaling is done by dragging the corner cubes. By default, uniform
59 scaling will be done. Hold down \c SHIFT before selecting any of the
60 corners to do non-uniform scaling. Uniform scaling towards a
61 corner-point can be accomplished by holding down \c CTRL before
62 clicking and dragging one of the cubes.
63
64 Rotation is done by dragging any of the 6 end-markers of the axis
65 cross. The initial drag direction decides which orientation the
66 rotation will be done in. Hold down \c SHIFT to do free-form
67 rotation around the sphere instead.
68
69
70 This is a big and complex dragger which needs a fair amount of
71 proper documentation when provided in end-user applications. If what
72 you are trying to accomplish in your application does not really
73 demand most of the features of this dragger, you are advised to
74 investigate whether or not any of the less complex draggers can
75 fulfill your requirements -- so you can provide an as simple as
76 possible user interface to your end-users.
77
78
79 For the application programmer's convenience, the Coin library also
80 provides a manipulator class called SoTransformerManip, which wraps
81 the SoTransformerDragger into the necessary mechanisms for making
82 direct insertion of this dragger into a scenegraph possible with
83 very little effort.
84
85 \sa SoTransformerManip
86 */
87
88 #include <Inventor/draggers/SoTransformerDragger.h>
89
90 #include <cstring>
91
92 #include <Inventor/nodes/SoAntiSquish.h>
93 #include <Inventor/nodes/SoLocateHighlight.h>
94 #include <Inventor/nodes/SoRotation.h>
95 #include <Inventor/nodes/SoSurroundScale.h>
96 #include <Inventor/nodes/SoSwitch.h>
97 #include <Inventor/nodes/SoTransform.h>
98 #include <Inventor/nodes/SoTranslation.h>
99 #include <Inventor/sensors/SoFieldSensor.h>
100 #include <Inventor/SbVec3f.h>
101 #include <Inventor/SbMatrix.h>
102 #include <Inventor/projectors/SbPlaneProjector.h>
103 #include <Inventor/projectors/SbLineProjector.h>
104 #include <Inventor/projectors/SbSphereSectionProjector.h>
105 #include <Inventor/projectors/SbCylinderPlaneProjector.h>
106 #include <Inventor/events/SoKeyboardEvent.h>
107 #include <Inventor/actions/SoSearchAction.h>
108 #include <Inventor/actions/SoGetMatrixAction.h>
109 #include <Inventor/lists/SoPathList.h>
110
111 #include <data/draggerDefaults/transformerDragger.h>
112
113 #include "coindefs.h" // COIN_STUB() & COIN_OBSOLETED()
114 #include "nodekits/SoSubKitP.h"
115 #include "SbBasicP.h"
116
117 // FIXME, bugs or missing features (pederb, 20000224):
118 // o some feedback is missing (mostly crosshair)
119 // o detect if disc or cylinder rotator should be used (disc-only right now)
120 //
121 // Also the translation feedback is a bit different from OIV. Coin
122 // always places the feedback axes at the center of the face being
123 // translated. OIV places them at the picked point. I think our
124 // strategy is better, since when switching between constrained
125 // translations and unconstrained translation, the OIV feedback axes
126 // can easily be positioned outside the face being dragged.
127 //
128 // MATRICES AND SPACES:
129 // There are many matrices and spaces that can take some time to get
130 // understand. The matrices calculated are:
131 //
132 // localToWorld = motionMatrix * draggerToWorld
133 // worldToLocal = worldToDragger * motionMatrix^-1
134 // draggerToWorld = worldToDragger^-1
135 //
136 // localToWorking = surroundScaleMatrix^-1
137 // workingToLocal = surroundScaleMatrix
138 //
139 // workingToWorld = surroundScaleMatrix * localToWorld
140 // worldToWorking = worldToLocal * surroundScaleMatrix
141 //
142 // boxPointInWorldSpace = p * surroundScaleMatrix * localToWorld
143 // worldPointInBoxSpace = p * worldToLocal * surroundScaleMatrix
144
145 /*!
146 \enum SoTransformerDragger::State
147
148 The various possible states the dragger might be in at any given
149 time. That is: either SoTransformerDragger::INACTIVE if there's no
150 interaction, or any of the other values to indicate what operation
151 the end-user is currently executing.
152 */
153
154 /*!
155 \var SoSFRotation SoTransformerDragger::rotation
156
157 This field is continuously updated to contain the orientation of the
158 dragger.
159 */
160 /*!
161 \var SoSFVec3f SoTransformerDragger::translation
162
163 The dragger's offset position from the local origo.
164 */
165 /*!
166 \var SoSFVec3f SoTransformerDragger::scaleFactor
167
168 Continuously updated to contain the current vector of scaling along
169 the X, Y and Z axes.
170 */
171
172 // FIXME: can't see what this is for -- investigate. 20011208 mortene.
173 // /*!
174 // \var SoSFFloat SoTransformerDragger::minDiscRotDot
175 // */
176
177 /*!
178 \var SoFieldSensor * SoTransformerDragger::translFieldSensor
179 \COININTERNAL
180 */
181 /*!
182 \var SoFieldSensor * SoTransformerDragger::scaleFieldSensor
183 \COININTERNAL
184 */
185 /*!
186 \var SoFieldSensor * SoTransformerDragger::rotateFieldSensor
187 \COININTERNAL
188 */
189 /*!
190 \var SoNodeList SoTransformerDragger::antiSquishList
191 \COININTERNAL
192 */
193
194 #define WHATKIND_NONE 0
195 #define WHATKIND_SCALE 1
196 #define WHATKIND_TRANSLATE 2
197 #define WHATKIND_ROTATE 3
198
199 #define CONSTRAINT_OFF 0
200 #define CONSTRAINT_WAIT 1
201 #define CONSTRAINT_X 2
202 #define CONSTRAINT_Y 3
203 #define CONSTRAINT_Z 4
204
205 #define KNOB_DISTANCE 1.25f // distance from center to rotate-knobs
206
207
208 #ifndef DOXYGEN_SKIP_THIS
209
210 class SoTransformerDraggerP {
211 public:
212 SbMatrix prevMotionMatrix;
213 SbVec3f prevWorldHitPt;
214 SbVec3f ctrlOffset;
215 SbBool ctrlDown;
216 SbBool shiftDown;
217 SbVec2f normalizedStartLocaterPosition;
218
219 SbBool locateHighlighting;
220 static int colinearThreshold;
221 int constraintState;
222
223 int whatkind;
224 int whatnum;
225 int dimension;
226 };
227
228 int SoTransformerDraggerP::colinearThreshold = 3; // FIXME: find default value from somewhere
229
230 #endif // DOXYGEN_SKIP_THIS
231
232 SO_KIT_SOURCE(SoTransformerDragger);
233
234 // doc in superclass
235 void
initClass(void)236 SoTransformerDragger::initClass(void)
237 {
238 SO_KIT_INTERNAL_INIT_CLASS(SoTransformerDragger, SO_FROM_INVENTOR_1);
239 SoTransformerDraggerP::colinearThreshold = 3;
240 }
241
242 void
build_catalog1(void)243 SoTransformerDragger::build_catalog1(void)
244 {
245 SO_KIT_ADD_CATALOG_ENTRY(surroundScale, SoSurroundScale, TRUE, topSeparator, overallStyle, TRUE);
246 SO_KIT_ADD_CATALOG_ENTRY(overallStyle, SoGroup, TRUE, topSeparator, geomSeparator, FALSE);
247 SO_KIT_ADD_CATALOG_ENTRY(translatorSep, SoSeparator, TRUE, topSeparator, rotatorSep, FALSE);
248 }
249
250 void
build_catalog2(void)251 SoTransformerDragger::build_catalog2(void)
252 {
253 SO_KIT_ADD_CATALOG_ENTRY(translator1Switch, SoSwitch, TRUE, translatorSep, translator2Switch, FALSE);
254 SO_KIT_ADD_CATALOG_ENTRY(translator1LocateGroup, SoLocateHighlight, TRUE, translator1Switch, translator1Active, FALSE);
255 SO_KIT_ADD_CATALOG_ENTRY(translator1, SoSeparator, TRUE, translator1LocateGroup, "", TRUE);
256 SO_KIT_ADD_CATALOG_ENTRY(translator1Active, SoSeparator, TRUE, translator1Switch, "", TRUE);
257 SO_KIT_ADD_CATALOG_ENTRY(translator2Switch, SoSwitch, TRUE, translatorSep, translator3Switch, FALSE);
258 SO_KIT_ADD_CATALOG_ENTRY(translator2LocateGroup, SoLocateHighlight, TRUE, translator2Switch, translator2Active, FALSE);
259 SO_KIT_ADD_CATALOG_ENTRY(translator2, SoSeparator, TRUE, translator2LocateGroup, "", TRUE);
260 SO_KIT_ADD_CATALOG_ENTRY(translator2Active, SoSeparator, TRUE, translator2Switch, "", TRUE);
261 SO_KIT_ADD_CATALOG_ENTRY(translator3Switch, SoSwitch, TRUE, translatorSep, translator4Switch, FALSE);
262 SO_KIT_ADD_CATALOG_ENTRY(translator3LocateGroup, SoLocateHighlight, TRUE, translator3Switch, translator3Active, FALSE);
263 SO_KIT_ADD_CATALOG_ENTRY(translator3, SoSeparator, TRUE, translator3LocateGroup, "", TRUE);
264 SO_KIT_ADD_CATALOG_ENTRY(translator3Active, SoSeparator, TRUE, translator3Switch, "", TRUE);
265 SO_KIT_ADD_CATALOG_ENTRY(translator4Switch, SoSwitch, TRUE, translatorSep, translator5Switch, FALSE);
266 SO_KIT_ADD_CATALOG_ENTRY(translator4LocateGroup, SoLocateHighlight, TRUE, translator4Switch, translator4Active, FALSE);
267 SO_KIT_ADD_CATALOG_ENTRY(translator4, SoSeparator, TRUE, translator4LocateGroup, "", TRUE);
268 SO_KIT_ADD_CATALOG_ENTRY(translator4Active, SoSeparator, TRUE, translator4Switch, "", TRUE);
269 SO_KIT_ADD_CATALOG_ENTRY(translator5Switch, SoSwitch, TRUE, translatorSep, translator6Switch, FALSE);
270 SO_KIT_ADD_CATALOG_ENTRY(translator5LocateGroup, SoLocateHighlight, TRUE, translator5Switch, translator5Active, FALSE);
271 SO_KIT_ADD_CATALOG_ENTRY(translator5, SoSeparator, TRUE, translator5LocateGroup, "", TRUE);
272 SO_KIT_ADD_CATALOG_ENTRY(translator5Active, SoSeparator, TRUE, translator5Switch, "", TRUE);
273 SO_KIT_ADD_CATALOG_ENTRY(translator6Switch, SoSwitch, TRUE, translatorSep, "", FALSE);
274 SO_KIT_ADD_CATALOG_ENTRY(translator6LocateGroup, SoLocateHighlight, TRUE, translator6Switch, translator6Active, FALSE);
275 SO_KIT_ADD_CATALOG_ENTRY(translator6, SoSeparator, TRUE, translator6LocateGroup, "", TRUE);
276 SO_KIT_ADD_CATALOG_ENTRY(translator6Active, SoSeparator, TRUE, translator6Switch, "", TRUE);
277 }
278
279 void
build_catalog3(void)280 SoTransformerDragger::build_catalog3(void)
281 {
282 SO_KIT_ADD_CATALOG_ENTRY(rotatorSep, SoSeparator, TRUE, topSeparator, scaleSep, FALSE);
283 SO_KIT_ADD_CATALOG_ENTRY(rotator1Switch, SoSwitch, TRUE, rotatorSep, rotator2Switch, FALSE);
284 SO_KIT_ADD_CATALOG_ENTRY(rotator1LocateGroup, SoLocateHighlight, TRUE, rotator1Switch, rotator1Active, FALSE);
285 SO_KIT_ADD_CATALOG_ENTRY(rotator1, SoSeparator, TRUE, rotator1LocateGroup, "", TRUE);
286 SO_KIT_ADD_CATALOG_ENTRY(rotator1Active, SoSeparator, TRUE, rotator1Switch, "", TRUE);
287 SO_KIT_ADD_CATALOG_ENTRY(rotator2Switch, SoSwitch, TRUE, rotatorSep, rotator3Switch, FALSE);
288 SO_KIT_ADD_CATALOG_ENTRY(rotator2LocateGroup, SoLocateHighlight, TRUE, rotator2Switch, rotator2Active, FALSE);
289 SO_KIT_ADD_CATALOG_ENTRY(rotator2, SoSeparator, TRUE, rotator2LocateGroup, "", TRUE);
290 SO_KIT_ADD_CATALOG_ENTRY(rotator2Active, SoSeparator, TRUE, rotator2Switch, "", TRUE);
291 SO_KIT_ADD_CATALOG_ENTRY(rotator3Switch, SoSwitch, TRUE, rotatorSep, rotator4Switch, FALSE);
292 SO_KIT_ADD_CATALOG_ENTRY(rotator3LocateGroup, SoLocateHighlight, TRUE, rotator3Switch, rotator3Active, FALSE);
293 SO_KIT_ADD_CATALOG_ENTRY(rotator3, SoSeparator, TRUE, rotator3LocateGroup, "", TRUE);
294 SO_KIT_ADD_CATALOG_ENTRY(rotator3Active, SoSeparator, TRUE, rotator3Switch, "", TRUE);
295 SO_KIT_ADD_CATALOG_ENTRY(rotator4Switch, SoSwitch, TRUE, rotatorSep, rotator5Switch, FALSE);
296 SO_KIT_ADD_CATALOG_ENTRY(rotator4LocateGroup, SoLocateHighlight, TRUE, rotator4Switch, rotator4Active, FALSE);
297 SO_KIT_ADD_CATALOG_ENTRY(rotator4, SoSeparator, TRUE, rotator4LocateGroup, "", TRUE);
298 SO_KIT_ADD_CATALOG_ENTRY(rotator4Active, SoSeparator, TRUE, rotator4Switch, "", TRUE);
299 SO_KIT_ADD_CATALOG_ENTRY(rotator5Switch, SoSwitch, TRUE, rotatorSep, rotator6Switch, FALSE);
300 SO_KIT_ADD_CATALOG_ENTRY(rotator5LocateGroup, SoLocateHighlight, TRUE, rotator5Switch, rotator5Active, FALSE);
301 SO_KIT_ADD_CATALOG_ENTRY(rotator5, SoSeparator, TRUE, rotator5LocateGroup, "", TRUE);
302 SO_KIT_ADD_CATALOG_ENTRY(rotator5Active, SoSeparator, TRUE, rotator5Switch, "", TRUE);
303 SO_KIT_ADD_CATALOG_ENTRY(rotator6Switch, SoSwitch, TRUE, rotatorSep, "", FALSE);
304 SO_KIT_ADD_CATALOG_ENTRY(rotator6LocateGroup, SoLocateHighlight, TRUE, rotator6Switch, rotator6Active, FALSE);
305 SO_KIT_ADD_CATALOG_ENTRY(rotator6, SoSeparator, TRUE, rotator6LocateGroup, "", TRUE);
306 SO_KIT_ADD_CATALOG_ENTRY(rotator6Active, SoSeparator, TRUE, rotator6Switch, "", TRUE);
307 }
308
309 void
build_catalog4(void)310 SoTransformerDragger::build_catalog4(void)
311 {
312 SO_KIT_ADD_CATALOG_ENTRY(scaleSep, SoSeparator, TRUE, topSeparator, circleFeedbackSep, FALSE);
313 SO_KIT_ADD_CATALOG_ENTRY(scale1Switch, SoSwitch, TRUE, scaleSep, scale2Switch, FALSE);
314 SO_KIT_ADD_CATALOG_ENTRY(scale1LocateGroup, SoLocateHighlight, TRUE, scale1Switch, scale1Active, FALSE);
315 SO_KIT_ADD_CATALOG_ENTRY(scale1, SoSeparator, TRUE, scale1LocateGroup, "", TRUE);
316 SO_KIT_ADD_CATALOG_ENTRY(scale1Active, SoSeparator, TRUE, scale1Switch, "", TRUE);
317 SO_KIT_ADD_CATALOG_ENTRY(scale2Switch, SoSwitch, TRUE, scaleSep, scale3Switch, FALSE);
318 SO_KIT_ADD_CATALOG_ENTRY(scale2LocateGroup, SoLocateHighlight, TRUE, scale2Switch, scale2Active, FALSE);
319 SO_KIT_ADD_CATALOG_ENTRY(scale2, SoSeparator, TRUE, scale2LocateGroup, "", TRUE);
320 SO_KIT_ADD_CATALOG_ENTRY(scale2Active, SoSeparator, TRUE, scale2Switch, "", TRUE);
321 SO_KIT_ADD_CATALOG_ENTRY(scale3Switch, SoSwitch, TRUE, scaleSep, scale4Switch, FALSE);
322 SO_KIT_ADD_CATALOG_ENTRY(scale3LocateGroup, SoLocateHighlight, TRUE, scale3Switch, scale3Active, FALSE);
323 SO_KIT_ADD_CATALOG_ENTRY(scale3, SoSeparator, TRUE, scale3LocateGroup, "", TRUE);
324 SO_KIT_ADD_CATALOG_ENTRY(scale3Active, SoSeparator, TRUE, scale3Switch, "", TRUE);
325 SO_KIT_ADD_CATALOG_ENTRY(scale4Switch, SoSwitch, TRUE, scaleSep, scale5Switch, FALSE);
326 SO_KIT_ADD_CATALOG_ENTRY(scale4LocateGroup, SoLocateHighlight, TRUE, scale4Switch, scale4Active, FALSE);
327 SO_KIT_ADD_CATALOG_ENTRY(scale4, SoSeparator, TRUE, scale4LocateGroup, "", TRUE);
328 SO_KIT_ADD_CATALOG_ENTRY(scale4Active, SoSeparator, TRUE, scale4Switch, "", TRUE);
329 SO_KIT_ADD_CATALOG_ENTRY(scale5Switch, SoSwitch, TRUE, scaleSep, scale6Switch, FALSE);
330 SO_KIT_ADD_CATALOG_ENTRY(scale5LocateGroup, SoLocateHighlight, TRUE, scale5Switch, scale5Active, FALSE);
331 SO_KIT_ADD_CATALOG_ENTRY(scale5, SoSeparator, TRUE, scale5LocateGroup, "", TRUE);
332 SO_KIT_ADD_CATALOG_ENTRY(scale5Active, SoSeparator, TRUE, scale5Switch, "", TRUE);
333 SO_KIT_ADD_CATALOG_ENTRY(scale6Switch, SoSwitch, TRUE, scaleSep, scale7Switch, FALSE);
334 SO_KIT_ADD_CATALOG_ENTRY(scale6LocateGroup, SoLocateHighlight, TRUE, scale6Switch, scale6Active, FALSE);
335 SO_KIT_ADD_CATALOG_ENTRY(scale6, SoSeparator, TRUE, scale6LocateGroup, "", TRUE);
336 SO_KIT_ADD_CATALOG_ENTRY(scale6Active, SoSeparator, TRUE, scale6Switch, "", TRUE);
337 SO_KIT_ADD_CATALOG_ENTRY(scale7Switch, SoSwitch, TRUE, scaleSep, scale8Switch, FALSE);
338 SO_KIT_ADD_CATALOG_ENTRY(scale7LocateGroup, SoLocateHighlight, TRUE, scale7Switch, scale7Active, FALSE);
339 SO_KIT_ADD_CATALOG_ENTRY(scale7, SoSeparator, TRUE, scale7LocateGroup, "", TRUE);
340 SO_KIT_ADD_CATALOG_ENTRY(scale7Active, SoSeparator, TRUE, scale7Switch, "", TRUE);
341 SO_KIT_ADD_CATALOG_ENTRY(scale8Switch, SoSwitch, TRUE, scaleSep, "", FALSE);
342 SO_KIT_ADD_CATALOG_ENTRY(scale8LocateGroup, SoLocateHighlight, TRUE, scale8Switch, scale8Active, FALSE);
343 SO_KIT_ADD_CATALOG_ENTRY(scale8, SoSeparator, TRUE, scale8LocateGroup, "", TRUE);
344 SO_KIT_ADD_CATALOG_ENTRY(scale8Active, SoSeparator, TRUE, scale8Switch, "", TRUE);
345 }
346
347 void
build_catalog5(void)348 SoTransformerDragger::build_catalog5(void)
349 {
350 SO_KIT_ADD_CATALOG_ENTRY(axisFeedbackSep, SoSeparator, TRUE, geomSeparator, translateBoxFeedbackSep, FALSE);
351 SO_KIT_ADD_CATALOG_ENTRY(axisFeedbackLocation, SoTranslation, TRUE, axisFeedbackSep, xAxisFeedbackSwitch, FALSE);
352 SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, yAxisFeedbackSwitch, FALSE);
353 SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackActive, SoSeparator, TRUE, xAxisFeedbackSwitch, xAxisFeedbackSelect, TRUE);
354 SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackSelect, SoSeparator, TRUE, xAxisFeedbackSwitch, xCrosshairFeedback, TRUE);
355 SO_KIT_ADD_CATALOG_ENTRY(xCrosshairFeedback, SoSeparator, TRUE, xAxisFeedbackSwitch, "", TRUE);
356 SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, zAxisFeedbackSwitch, FALSE);
357 SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackActive, SoSeparator, TRUE, yAxisFeedbackSwitch, yAxisFeedbackSelect, TRUE);
358 SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackSelect, SoSeparator, TRUE, yAxisFeedbackSwitch, yCrosshairFeedback, TRUE);
359 SO_KIT_ADD_CATALOG_ENTRY(yCrosshairFeedback, SoSeparator, TRUE, yAxisFeedbackSwitch, "", TRUE);
360 SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, "", FALSE);
361 SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackActive, SoSeparator, TRUE, zAxisFeedbackSwitch, zAxisFeedbackSelect, TRUE);
362 SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackSelect, SoSeparator, TRUE, zAxisFeedbackSwitch, zCrosshairFeedback, TRUE);
363 SO_KIT_ADD_CATALOG_ENTRY(zCrosshairFeedback, SoSeparator, TRUE, zAxisFeedbackSwitch, "", TRUE);
364 SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackSep, SoSeparator, TRUE, geomSeparator, scaleBoxFeedbackSwitch, FALSE);
365 SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackSwitch, SoSwitch, TRUE, translateBoxFeedbackSep, "", FALSE);
366 SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackRotation, SoRotation, TRUE, translateBoxFeedbackSwitch, translateBoxFeedback, FALSE);
367 SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedback, SoSeparator, TRUE, translateBoxFeedbackSwitch, "", TRUE);
368 SO_KIT_ADD_CATALOG_ENTRY(scaleBoxFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posXWallFeedbackSwitch, FALSE);
369 SO_KIT_ADD_CATALOG_ENTRY(scaleBoxFeedback, SoSeparator, TRUE, scaleBoxFeedbackSwitch, "", TRUE);
370 SO_KIT_ADD_CATALOG_ENTRY(posXWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posYWallFeedbackSwitch, FALSE);
371 SO_KIT_ADD_CATALOG_ENTRY(posXWallFeedback, SoSeparator, TRUE, posXWallFeedbackSwitch, posXRoundWallFeedback, TRUE);
372 SO_KIT_ADD_CATALOG_ENTRY(posXRoundWallFeedback, SoSeparator, TRUE, posXWallFeedbackSwitch, "", TRUE);
373 SO_KIT_ADD_CATALOG_ENTRY(posYWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posZWallFeedbackSwitch, FALSE);
374 SO_KIT_ADD_CATALOG_ENTRY(posYWallFeedback, SoSeparator, TRUE, posYWallFeedbackSwitch, posYRoundWallFeedback, TRUE);
375 SO_KIT_ADD_CATALOG_ENTRY(posYRoundWallFeedback, SoSeparator, TRUE, posYWallFeedbackSwitch, "", TRUE);
376 SO_KIT_ADD_CATALOG_ENTRY(posZWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negXWallFeedbackSwitch, FALSE);
377 SO_KIT_ADD_CATALOG_ENTRY(posZWallFeedback, SoSeparator, TRUE, posZWallFeedbackSwitch, posZRoundWallFeedback, TRUE);
378 SO_KIT_ADD_CATALOG_ENTRY(posZRoundWallFeedback, SoSeparator, TRUE, posZWallFeedbackSwitch, "", TRUE);
379 }
380
381 void
build_catalog6(void)382 SoTransformerDragger::build_catalog6(void)
383 {
384 SO_KIT_ADD_CATALOG_ENTRY(negXWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negYWallFeedbackSwitch, FALSE);
385 SO_KIT_ADD_CATALOG_ENTRY(negXWallFeedback, SoSeparator, TRUE, negXWallFeedbackSwitch, negXRoundWallFeedback, TRUE);
386 SO_KIT_ADD_CATALOG_ENTRY(negXRoundWallFeedback, SoSeparator, TRUE, negXWallFeedbackSwitch, "", TRUE);
387 SO_KIT_ADD_CATALOG_ENTRY(negYWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negZWallFeedbackSwitch, FALSE);
388 SO_KIT_ADD_CATALOG_ENTRY(negYWallFeedback, SoSeparator, TRUE, negYWallFeedbackSwitch, negYRoundWallFeedback, TRUE);
389 SO_KIT_ADD_CATALOG_ENTRY(negYRoundWallFeedback, SoSeparator, TRUE, negYWallFeedbackSwitch, "", TRUE);
390 SO_KIT_ADD_CATALOG_ENTRY(negZWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, radialFeedbackSwitch, FALSE);
391 SO_KIT_ADD_CATALOG_ENTRY(negZWallFeedback, SoSeparator, TRUE, negZWallFeedbackSwitch, negZRoundWallFeedback, TRUE);
392 SO_KIT_ADD_CATALOG_ENTRY(negZRoundWallFeedback, SoSeparator, TRUE, negZWallFeedbackSwitch, "", TRUE);
393 SO_KIT_ADD_CATALOG_ENTRY(radialFeedbackSwitch, SoSwitch, TRUE, geomSeparator, "", FALSE);
394 SO_KIT_ADD_CATALOG_ENTRY(radialFeedback, SoSeparator, TRUE, radialFeedbackSwitch, "", TRUE);
395 SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackSep, SoSeparator, TRUE, topSeparator, "", FALSE);
396 SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackTransformSwitch, SoSwitch, TRUE, circleFeedbackSep, xCircleFeedbackSwitch, FALSE);
397 SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackAntiSquish, SoAntiSquish, TRUE, circleFeedbackTransformSwitch, circleFeedbackTransform, FALSE);
398 SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackTransform, SoTransform, TRUE, circleFeedbackTransformSwitch, "", FALSE);
399 SO_KIT_ADD_CATALOG_ENTRY(xCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, yCircleFeedbackSwitch, FALSE);
400 SO_KIT_ADD_CATALOG_ENTRY(xCircleFeedback, SoSeparator, TRUE, xCircleFeedbackSwitch, "", TRUE);
401 SO_KIT_ADD_CATALOG_ENTRY(yCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, zCircleFeedbackSwitch, FALSE);
402 SO_KIT_ADD_CATALOG_ENTRY(yCircleFeedback, SoSeparator, TRUE, yCircleFeedbackSwitch, "", TRUE);
403 SO_KIT_ADD_CATALOG_ENTRY(zCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, "", FALSE);
404 SO_KIT_ADD_CATALOG_ENTRY(zCircleFeedback, SoSeparator, TRUE, zCircleFeedbackSwitch, "", TRUE);
405 }
406
407 #define PRIVATE(obj) ((obj)->pimpl)
408 #define THISP(d) static_cast<SoTransformerDragger *>(d)
409
410 // FIXME: document which parts need to be present in the geometry
411 // scenegraph, and what role they play in the dragger. 20010913 mortene.
412 /*!
413 \DRAGGER_CONSTRUCTOR
414
415 \NODEKIT_PRE_DIAGRAM
416
417 \verbatim
418 CLASS SoTransformerDragger
419 -->"this"
420 "callbackList"
421 "topSeparator"
422 "motionMatrix"
423 --> "surroundScale"
424 --> "overallStyle"
425 "geomSeparator"
426 --> "axisFeedbackSep"
427 --> "axisFeedbackLocation"
428 --> "xAxisFeedbackSwitch"
429 --> "xAxisFeedbackActive"
430 --> "xAxisFeedbackSelect"
431 --> "xCrosshairFeedback"
432 --> "yAxisFeedbackSwitch"
433 --> "yAxisFeedbackActive"
434 --> "yAxisFeedbackSelect"
435 --> "yCrosshairFeedback"
436 --> "zAxisFeedbackSwitch"
437 --> "zAxisFeedbackActive"
438 --> "zAxisFeedbackSelect"
439 --> "zCrosshairFeedback"
440 --> "translateBoxFeedbackSep"
441 --> "translateBoxFeedbackSwitch"
442 --> "translateBoxFeedbackRotation"
443 --> "translateBoxFeedback"
444 --> "scaleBoxFeedbackSwitch"
445 --> "scaleBoxFeedback"
446 --> "posXWallFeedbackSwitch"
447 --> "posXWallFeedback"
448 --> "posXRoundWallFeedback"
449 --> "posYWallFeedbackSwitch"
450 --> "posYWallFeedback"
451 --> "posYRoundWallFeedback"
452 --> "posZWallFeedbackSwitch"
453 --> "posZWallFeedback"
454 --> "posZRoundWallFeedback"
455 --> "negXWallFeedbackSwitch"
456 --> "negXWallFeedback"
457 --> "negXRoundWallFeedback"
458 --> "negYWallFeedbackSwitch"
459 --> "negYWallFeedback"
460 --> "negYRoundWallFeedback"
461 --> "negZWallFeedbackSwitch"
462 --> "negZWallFeedback"
463 --> "negZRoundWallFeedback"
464 --> "radialFeedbackSwitch"
465 --> "radialFeedback"
466 --> "translatorSep"
467 --> "translator1Switch"
468 --> "translator1LocateGroup"
469 --> "translator1"
470 --> "translator1Active"
471 --> "translator2Switch"
472 --> "translator2LocateGroup"
473 --> "translator2"
474 --> "translator2Active"
475 --> "translator3Switch"
476 --> "translator3LocateGroup"
477 --> "translator3"
478 --> "translator3Active"
479 --> "translator4Switch"
480 --> "translator4LocateGroup"
481 --> "translator4"
482 --> "translator4Active"
483 --> "translator5Switch"
484 --> "translator5LocateGroup"
485 --> "translator5"
486 --> "translator5Active"
487 --> "translator6Switch"
488 --> "translator6LocateGroup"
489 --> "translator6"
490 --> "translator6Active"
491 --> "rotatorSep"
492 --> "rotator1Switch"
493 --> "rotator1LocateGroup"
494 --> "rotator1"
495 --> "rotator1Active"
496 --> "rotator2Switch"
497 --> "rotator2LocateGroup"
498 --> "rotator2"
499 --> "rotator2Active"
500 --> "rotator3Switch"
501 --> "rotator3LocateGroup"
502 --> "rotator3"
503 --> "rotator3Active"
504 --> "rotator4Switch"
505 --> "rotator4LocateGroup"
506 --> "rotator4"
507 --> "rotator4Active"
508 --> "rotator5Switch"
509 --> "rotator5LocateGroup"
510 --> "rotator5"
511 --> "rotator5Active"
512 --> "rotator6Switch"
513 --> "rotator6LocateGroup"
514 --> "rotator6"
515 --> "rotator6Active"
516 --> "scaleSep"
517 --> "scale1Switch"
518 --> "scale1LocateGroup"
519 --> "scale1"
520 --> "scale1Active"
521 --> "scale2Switch"
522 --> "scale2LocateGroup"
523 --> "scale2"
524 --> "scale2Active"
525 --> "scale3Switch"
526 --> "scale3LocateGroup"
527 --> "scale3"
528 --> "scale3Active"
529 --> "scale4Switch"
530 --> "scale4LocateGroup"
531 --> "scale4"
532 --> "scale4Active"
533 --> "scale5Switch"
534 --> "scale5LocateGroup"
535 --> "scale5"
536 --> "scale5Active"
537 --> "scale6Switch"
538 --> "scale6LocateGroup"
539 --> "scale6"
540 --> "scale6Active"
541 --> "scale7Switch"
542 --> "scale7LocateGroup"
543 --> "scale7"
544 --> "scale7Active"
545 --> "scale8Switch"
546 --> "scale8LocateGroup"
547 --> "scale8"
548 --> "scale8Active"
549 --> "circleFeedbackSep"
550 --> "circleFeedbackTransformSwitch"
551 --> "circleFeedbackAntiSquish"
552 --> "circleFeedbackTransform"
553 --> "xCircleFeedbackSwitch"
554 --> "xCircleFeedback"
555 --> "yCircleFeedbackSwitch"
556 --> "yCircleFeedback"
557 --> "zCircleFeedbackSwitch"
558 --> "zCircleFeedback"
559 \endverbatim
560
561 \NODEKIT_POST_DIAGRAM
562
563
564 \NODEKIT_PRE_TABLE
565
566 \verbatim
567 CLASS SoTransformerDragger
568 PVT "this", SoTransformerDragger ---
569 "callbackList", SoNodeKitListPart [ SoCallback, SoEventCallback ]
570 PVT "topSeparator", SoSeparator ---
571 PVT "motionMatrix", SoMatrixTransform ---
572 "surroundScale", SoSurroundScale ---
573 PVT "overallStyle", SoGroup ---
574 PVT "geomSeparator", SoSeparator ---
575 PVT "translatorSep", SoSeparator ---
576 PVT "translator1Switch", SoSwitch ---
577 PVT "translator1LocateGroup", SoLocateHighlight ---
578 "translator1", SoSeparator ---
579 "translator1Active", SoSeparator ---
580 PVT "translator2Switch", SoSwitch ---
581 PVT "translator2LocateGroup", SoLocateHighlight ---
582 "translator2", SoSeparator ---
583 "translator2Active", SoSeparator ---
584 PVT "translator3Switch", SoSwitch ---
585 PVT "translator3LocateGroup", SoLocateHighlight ---
586 "translator3", SoSeparator ---
587 "translator3Active", SoSeparator ---
588 PVT "translator4Switch", SoSwitch ---
589 PVT "translator4LocateGroup", SoLocateHighlight ---
590 "translator4", SoSeparator ---
591 "translator4Active", SoSeparator ---
592 PVT "translator5Switch", SoSwitch ---
593 PVT "translator5LocateGroup", SoLocateHighlight ---
594 "translator5", SoSeparator ---
595 "translator5Active", SoSeparator ---
596 PVT "translator6Switch", SoSwitch ---
597 PVT "translator6LocateGroup", SoLocateHighlight ---
598 "translator6", SoSeparator ---
599 "translator6Active", SoSeparator ---
600 PVT "rotatorSep", SoSeparator ---
601 PVT "rotator1Switch", SoSwitch ---
602 PVT "rotator1LocateGroup", SoLocateHighlight ---
603 "rotator1", SoSeparator ---
604 "rotator1Active", SoSeparator ---
605 PVT "rotator2Switch", SoSwitch ---
606 PVT "rotator2LocateGroup", SoLocateHighlight ---
607 "rotator2", SoSeparator ---
608 "rotator2Active", SoSeparator ---
609 PVT "rotator3Switch", SoSwitch ---
610 PVT "rotator3LocateGroup", SoLocateHighlight ---
611 "rotator3", SoSeparator ---
612 "rotator3Active", SoSeparator ---
613 PVT "rotator4Switch", SoSwitch ---
614 PVT "rotator4LocateGroup", SoLocateHighlight ---
615 "rotator4", SoSeparator ---
616 "rotator4Active", SoSeparator ---
617 PVT "rotator5Switch", SoSwitch ---
618 PVT "rotator5LocateGroup", SoLocateHighlight ---
619 "rotator5", SoSeparator ---
620 "rotator5Active", SoSeparator ---
621 PVT "rotator6Switch", SoSwitch ---
622 PVT "rotator6LocateGroup", SoLocateHighlight ---
623 "rotator6", SoSeparator ---
624 "rotator6Active", SoSeparator ---
625 PVT "scaleSep", SoSeparator ---
626 PVT "scale1Switch", SoSwitch ---
627 PVT "scale1LocateGroup", SoLocateHighlight ---
628 "scale1", SoSeparator ---
629 "scale1Active", SoSeparator ---
630 PVT "scale2Switch", SoSwitch ---
631 PVT "scale2LocateGroup", SoLocateHighlight ---
632 "scale2", SoSeparator ---
633 "scale2Active", SoSeparator ---
634 PVT "scale3Switch", SoSwitch ---
635 PVT "scale3LocateGroup", SoLocateHighlight ---
636 "scale3", SoSeparator ---
637 "scale3Active", SoSeparator ---
638 PVT "scale4Switch", SoSwitch ---
639 PVT "scale4LocateGroup", SoLocateHighlight ---
640 "scale4", SoSeparator ---
641 "scale4Active", SoSeparator ---
642 PVT "scale5Switch", SoSwitch ---
643 PVT "scale5LocateGroup", SoLocateHighlight ---
644 "scale5", SoSeparator ---
645 "scale5Active", SoSeparator ---
646 PVT "scale6Switch", SoSwitch ---
647 PVT "scale6LocateGroup", SoLocateHighlight ---
648 "scale6", SoSeparator ---
649 "scale6Active", SoSeparator ---
650 PVT "scale7Switch", SoSwitch ---
651 PVT "scale7LocateGroup", SoLocateHighlight ---
652 "scale7", SoSeparator ---
653 "scale7Active", SoSeparator ---
654 PVT "scale8Switch", SoSwitch ---
655 PVT "scale8LocateGroup", SoLocateHighlight ---
656 "scale8", SoSeparator ---
657 "scale8Active", SoSeparator ---
658 PVT "circleFeedbackSep", SoSeparator ---
659 PVT "circleFeedbackTransformSwitch", SoSwitch ---
660 PVT "circleFeedbackAntiSquish", SoAntiSquish ---
661 PVT "circleFeedbackTransform", SoTransform ---
662 PVT "xCircleFeedbackSwitch", SoSwitch ---
663 "xCircleFeedback", SoSeparator ---
664 PVT "yCircleFeedbackSwitch", SoSwitch ---
665 "yCircleFeedback", SoSeparator ---
666 PVT "zCircleFeedbackSwitch", SoSwitch ---
667 "zCircleFeedback", SoSeparator ---
668 PVT "axisFeedbackSep", SoSeparator ---
669 PVT "axisFeedbackLocation", SoTranslation ---
670 PVT "xAxisFeedbackSwitch", SoSwitch ---
671 "xAxisFeedbackActive", SoSeparator ---
672 "xAxisFeedbackSelect", SoSeparator ---
673 "xCrosshairFeedback", SoSeparator ---
674 PVT "yAxisFeedbackSwitch", SoSwitch ---
675 "yAxisFeedbackActive", SoSeparator ---
676 "yAxisFeedbackSelect", SoSeparator ---
677 "yCrosshairFeedback", SoSeparator ---
678 PVT "zAxisFeedbackSwitch", SoSwitch ---
679 "zAxisFeedbackActive", SoSeparator ---
680 "zAxisFeedbackSelect", SoSeparator ---
681 "zCrosshairFeedback", SoSeparator ---
682 PVT "translateBoxFeedbackSep", SoSeparator ---
683 PVT "translateBoxFeedbackSwitch", SoSwitch ---
684 PVT "translateBoxFeedbackRotation", SoRotation ---
685 "translateBoxFeedback", SoSeparator ---
686 PVT "scaleBoxFeedbackSwitch", SoSwitch ---
687 "scaleBoxFeedback", SoSeparator ---
688 PVT "posXWallFeedbackSwitch", SoSwitch ---
689 "posXWallFeedback", SoSeparator ---
690 "posXRoundWallFeedback", SoSeparator ---
691 PVT "posYWallFeedbackSwitch", SoSwitch ---
692 "posYWallFeedback", SoSeparator ---
693 "posYRoundWallFeedback", SoSeparator ---
694 PVT "posZWallFeedbackSwitch", SoSwitch ---
695 "posZWallFeedback", SoSeparator ---
696 "posZRoundWallFeedback", SoSeparator ---
697 PVT "negXWallFeedbackSwitch", SoSwitch ---
698 "negXWallFeedback", SoSeparator ---
699 "negXRoundWallFeedback", SoSeparator ---
700 PVT "negYWallFeedbackSwitch", SoSwitch ---
701 "negYWallFeedback", SoSeparator ---
702 "negYRoundWallFeedback", SoSeparator ---
703 PVT "negZWallFeedbackSwitch", SoSwitch ---
704 "negZWallFeedback", SoSeparator ---
705 "negZRoundWallFeedback", SoSeparator ---
706 PVT "radialFeedbackSwitch", SoSwitch ---
707 "radialFeedback", SoSeparator ---
708 \endverbatim
709
710 \NODEKIT_POST_TABLE
711 */
SoTransformerDragger(void)712 SoTransformerDragger::SoTransformerDragger(void)
713 {
714 SO_KIT_INTERNAL_CONSTRUCTOR(SoTransformerDragger);
715
716 // split-up to avoid one huge method
717 this->build_catalog1();
718 this->build_catalog2();
719 this->build_catalog3();
720 this->build_catalog4();
721 this->build_catalog5();
722 this->build_catalog6();
723
724 if (SO_KIT_IS_FIRST_INSTANCE()) {
725 SoInteractionKit::readDefaultParts("transformerDragger.iv",
726 TRANSFORMERDRAGGER_draggergeometry,
727 static_cast<int>(strlen(TRANSFORMERDRAGGER_draggergeometry)));
728 }
729
730 SO_KIT_ADD_FIELD(rotation, (SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f)));
731 SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
732 SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
733 // FIXME: it doesn't look like this field is actually used or set
734 // anywhere else but here. Investigate. 20011208 mortene.
735 SO_KIT_ADD_FIELD(minDiscRotDot, (0.025f));
736
737 SO_KIT_INIT_INSTANCE();
738
739 this->setPartAsDefault("overallStyle", "transformerOverallStyle");
740 this->setPartAsDefault("translator1", "transformerTranslator1");
741 this->setPartAsDefault("translator2", "transformerTranslator2");
742 this->setPartAsDefault("translator3", "transformerTranslator3");
743 this->setPartAsDefault("translator4", "transformerTranslator4");
744 this->setPartAsDefault("translator5", "transformerTranslator5");
745 this->setPartAsDefault("translator6", "transformerTranslator6");
746 this->setPartAsDefault("translator1Active", "transformerTranslator1Active");
747 this->setPartAsDefault("translator2Active", "transformerTranslator2Active");
748 this->setPartAsDefault("translator3Active", "transformerTranslator3Active");
749 this->setPartAsDefault("translator4Active", "transformerTranslator4Active");
750 this->setPartAsDefault("translator5Active", "transformerTranslator5Active");
751 this->setPartAsDefault("translator6Active", "transformerTranslator6Active");
752 this->setPartAsDefault("rotator1", "transformerRotator1");
753 this->setPartAsDefault("rotator2", "transformerRotator2");
754 this->setPartAsDefault("rotator3", "transformerRotator3");
755 this->setPartAsDefault("rotator4", "transformerRotator4");
756 this->setPartAsDefault("rotator5", "transformerRotator5");
757 this->setPartAsDefault("rotator6", "transformerRotator6");
758 this->setPartAsDefault("rotator1Active", "transformerRotator1Active");
759 this->setPartAsDefault("rotator2Active", "transformerRotator2Active");
760 this->setPartAsDefault("rotator3Active", "transformerRotator3Active");
761 this->setPartAsDefault("rotator4Active", "transformerRotator4Active");
762 this->setPartAsDefault("rotator5Active", "transformerRotator5Active");
763 this->setPartAsDefault("rotator6Active", "transformerRotator6Active");
764 this->setPartAsDefault("scale1", "transformerScale1");
765 this->setPartAsDefault("scale2", "transformerScale2");
766 this->setPartAsDefault("scale3", "transformerScale3");
767 this->setPartAsDefault("scale4", "transformerScale4");
768 this->setPartAsDefault("scale5", "transformerScale5");
769 this->setPartAsDefault("scale6", "transformerScale6");
770 this->setPartAsDefault("scale7", "transformerScale7");
771 this->setPartAsDefault("scale8", "transformerScale8");
772 this->setPartAsDefault("scale1Active", "transformerScale1Active");
773 this->setPartAsDefault("scale2Active", "transformerScale2Active");
774 this->setPartAsDefault("scale3Active", "transformerScale3Active");
775 this->setPartAsDefault("scale4Active", "transformerScale4Active");
776 this->setPartAsDefault("scale5Active", "transformerScale5Active");
777 this->setPartAsDefault("scale6Active", "transformerScale6Active");
778 this->setPartAsDefault("scale7Active", "transformerScale7Active");
779 this->setPartAsDefault("scale8Active", "transformerScale8Active");
780 this->setPartAsDefault("xAxisFeedbackActive", "transformerXAxisFeedbackActive");
781 this->setPartAsDefault("xAxisFeedbackSelect", "transformerXAxisFeedbackSelect");
782 this->setPartAsDefault("yAxisFeedbackActive", "transformerYAxisFeedbackActive");
783 this->setPartAsDefault("yAxisFeedbackSelect", "transformerYAxisFeedbackSelect");
784 this->setPartAsDefault("zAxisFeedbackActive", "transformerZAxisFeedbackActive");
785 this->setPartAsDefault("zAxisFeedbackSelect", "transformerZAxisFeedbackSelect");
786 this->setPartAsDefault("xCrosshairFeedback", "transformerXCrosshairFeedback");
787 this->setPartAsDefault("yCrosshairFeedback", "transformerYCrosshairFeedback");
788 this->setPartAsDefault("zCrosshairFeedback", "transformerZCrosshairFeedback");
789 this->setPartAsDefault("xCircleFeedback", "transformerXCircleFeedback");
790 this->setPartAsDefault("yCircleFeedback", "transformerYCircleFeedback");
791 this->setPartAsDefault("zCircleFeedback", "transformerZCircleFeedback");
792 this->setPartAsDefault("radialFeedback", "transformerRadialFeedback");
793 this->setPartAsDefault("translateBoxFeedback", "transformerTranslateBoxFeedback");
794
795 this->setPartAsDefault("scaleBoxFeedback", "transformerScaleBoxFeedback");
796 this->setPartAsDefault("posXWallFeedback", "transformerPosXWallFeedback");
797 this->setPartAsDefault("posYWallFeedback", "transformerPosYWallFeedback");
798 this->setPartAsDefault("posZWallFeedback", "transformerPosZWallFeedback");
799 this->setPartAsDefault("negXWallFeedback", "transformerNegXWallFeedback");
800 this->setPartAsDefault("negYWallFeedback", "transformerNegYWallFeedback");
801 this->setPartAsDefault("negZWallFeedback", "transformerNegZWallFeedback");
802 this->setPartAsDefault("posXRoundWallFeedback", "transformerPosXRoundWallFeedback");
803 this->setPartAsDefault("posYRoundWallFeedback", "transformerPosYRoundWallFeedback");
804 this->setPartAsDefault("posZRoundWallFeedback", "transformerPosZRoundWallFeedback");
805 this->setPartAsDefault("negXRoundWallFeedback", "transformerNegXRoundWallFeedback");
806 this->setPartAsDefault("negYRoundWallFeedback", "transformerNegYRoundWallFeedback");
807 this->setPartAsDefault("negZRoundWallFeedback", "transformerNegZRoundWallFeedback");
808
809 this->state = INACTIVE;
810 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
811 // FIXME: according to SGI classdoc, this flag is supposed to be
812 // default TRUE? Investigate. 20011208 mortene.
813 PRIVATE(this)->locateHighlighting = FALSE;
814 PRIVATE(this)->whatkind = WHATKIND_NONE;
815 PRIVATE(this)->whatnum = -1;
816
817 this->setAllPartSwitches(0, 0, 0);
818
819 this->addStartCallback(SoTransformerDragger::startCB);
820 this->addMotionCallback(SoTransformerDragger::motionCB);
821 this->addFinishCallback(SoTransformerDragger::finishCB);
822 this->addValueChangedCallback(SoTransformerDragger::valueChangedCB);
823 this->addOtherEventCallback(SoTransformerDragger::metaKeyChangeCB);
824
825 this->planeProj = new SbPlaneProjector;
826 this->lineProj = new SbLineProjector;
827 this->sphereProj = new SbSphereSectionProjector;
828 this->cylProj = new SbCylinderPlaneProjector;
829
830 this->translFieldSensor = new SoFieldSensor(SoTransformerDragger::fieldSensorCB, this);
831 this->translFieldSensor->setPriority(0);
832 this->scaleFieldSensor = new SoFieldSensor(SoTransformerDragger::fieldSensorCB, this);
833 this->scaleFieldSensor->setPriority(0);
834 this->rotateFieldSensor = new SoFieldSensor(SoTransformerDragger::fieldSensorCB, this);
835 this->rotateFieldSensor->setPriority(0);
836
837 this->setUpConnections(TRUE, TRUE);
838
839 // make sure these are not written if they have the default value.
840 // FIXME: investigate why this is needed. There must be a
841 // notification that is sent somewhere that causes the fields to
842 // become non-default. pederb, 2003-04-01
843 this->translatorSep.setDefault(TRUE);
844 this->rotatorSep.setDefault(TRUE);
845 this->scaleSep.setDefault(TRUE);
846 this->translateBoxFeedbackSep.setDefault(TRUE);
847 this->axisFeedbackSep.setDefault(TRUE);
848 this->scale8LocateGroup.setDefault(TRUE);
849 this->scale7LocateGroup.setDefault(TRUE);
850 this->circleFeedbackSep.setDefault(TRUE);
851 }
852
853 /*!
854 Protected destructor.
855
856 (Dragger classes are derived from SoBase, so they are reference
857 counted and automatically destroyed when their reference count goes
858 to 0.)
859 */
~SoTransformerDragger()860 SoTransformerDragger::~SoTransformerDragger()
861 {
862 delete this->planeProj;
863 delete this->lineProj;
864 delete this->sphereProj;
865 delete this->cylProj;
866
867 delete this->translFieldSensor;
868 delete this->scaleFieldSensor;
869 delete this->rotateFieldSensor;
870 }
871
872 // Doc in super.
873 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)874 SoTransformerDragger::setUpConnections(SbBool onoff, SbBool doitalways)
875 {
876 if (!doitalways && this->connectionsSetUp == onoff) return onoff;
877
878 if (onoff) {
879 inherited::setUpConnections(onoff, doitalways);
880
881 SoTransformerDragger::fieldSensorCB(this, NULL);
882
883 if (this->translFieldSensor->getAttachedField() != &this->translation) {
884 this->translFieldSensor->attach(&this->translation);
885 }
886 if (this->scaleFieldSensor->getAttachedField() != &this->scaleFactor) {
887 this->scaleFieldSensor->attach(&this->scaleFactor);
888 }
889 if (this->rotateFieldSensor->getAttachedField() != &this->rotation) {
890 this->rotateFieldSensor->attach(&this->rotation);
891 }
892 }
893 else {
894 if (this->translFieldSensor->getAttachedField() != NULL) {
895 this->translFieldSensor->detach();
896 }
897 if (this->scaleFieldSensor->getAttachedField() != NULL) {
898 this->scaleFieldSensor->detach();
899 }
900 if (this->rotateFieldSensor->getAttachedField() != NULL) {
901 this->rotateFieldSensor->detach();
902 }
903 inherited::setUpConnections(onoff, doitalways);
904 }
905 return !(this->connectionsSetUp = onoff);
906 }
907
908 // Convenience method used to call setDefault on similar fields.
909 //
910 // Note: keep the function name prefix to avoid name clashes with
911 // other dragger .cpp files for "--enable-compact" builds.
912 //
913 // FIXME: should collect these methods in a common method visible to
914 // all draggers implementing the exact same functionality. 20010826 mortene.
915 static void
SoTransformerDragger_set_default(SoDragger * dragger,const char * fmt,int minval,int maxval)916 SoTransformerDragger_set_default(SoDragger * dragger, const char * fmt,
917 int minval, int maxval)
918 {
919 SbString str;
920 for (int i = minval; i <= maxval; i++) {
921 str.sprintf(fmt, i);
922 SoField * f = dragger->getField(str.getString());
923 assert(f);
924 f->setDefault(TRUE);
925 }
926 }
927
928 // Doc in superclass.
929 void
setDefaultOnNonWritingFields(void)930 SoTransformerDragger::setDefaultOnNonWritingFields(void)
931 {
932 this->surroundScale.setDefault(TRUE);
933 this->circleFeedbackAntiSquish.setDefault(TRUE);
934 this->circleFeedbackTransform.setDefault(TRUE);
935 this->axisFeedbackLocation.setDefault(TRUE);
936 this->translateBoxFeedbackRotation.setDefault(TRUE);
937
938 SoTransformerDragger_set_default(this, "translator%dLocateGroup", 1, 6);
939 SoTransformerDragger_set_default(this, "rotator%dLocateGroup", 1, 6);
940 SoTransformerDragger_set_default(this, "scale%dLocateGroup", 1, 6);
941
942 inherited::setDefaultOnNonWritingFields();
943 }
944
945 /*! \COININTERNAL */
946 void
fieldSensorCB(void * d,SoSensor *)947 SoTransformerDragger::fieldSensorCB(void *d, SoSensor *)
948 {
949 SoTransformerDragger * thisp = THISP(d);
950 SbMatrix matrix = thisp->getMotionMatrix();
951 thisp->workFieldsIntoTransform(matrix);
952 thisp->setMotionMatrix(matrix);
953 }
954
955 /*! \COININTERNAL */
956 void
valueChangedCB(void *,SoDragger * d)957 SoTransformerDragger::valueChangedCB(void *, SoDragger * d)
958 {
959 SoTransformerDragger * thisp = THISP(d);
960 SbMatrix matrix = thisp->getMotionMatrix();
961 SbVec3f trans, scale;
962 SbRotation rot, scaleOrient;
963 matrix.getTransform(trans, rot, scale, scaleOrient);
964
965 thisp->translFieldSensor->detach();
966 if (thisp->translation.getValue() != trans)
967 thisp->translation = trans;
968 thisp->translFieldSensor->attach(&thisp->translation);
969
970 thisp->scaleFieldSensor->detach();
971 if (thisp->scaleFactor.getValue() != scale)
972 thisp->scaleFactor = scale;
973 thisp->scaleFieldSensor->attach(&thisp->scaleFactor);
974
975 thisp->rotateFieldSensor->detach();
976 if (thisp->rotation.getValue() != rot) {
977 thisp->rotation = rot;
978 }
979 thisp->rotateFieldSensor->attach(&thisp->rotation);
980 }
981
982 /*!
983 Returns an indicator for the current operation executed on the
984 dragger by the end-user -- or SoTransformerDragger::INACTIVE if
985 none.
986 */
987 SoTransformerDragger::State
getCurrentState(void)988 SoTransformerDragger::getCurrentState(void)
989 {
990 return this->state;
991 }
992
993 void
unsquishKnobs(void)994 SoTransformerDragger::unsquishKnobs(void)
995 {
996 this->updateAntiSquishList();
997 }
998
999 SbBool
isLocateHighlighting(void)1000 SoTransformerDragger::isLocateHighlighting(void)
1001 {
1002 return PRIVATE(this)->locateHighlighting;
1003 }
1004
1005 void
setLocateHighlighting(SbBool onoff)1006 SoTransformerDragger::setLocateHighlighting(SbBool onoff)
1007 {
1008 // FIXME: I can't see that this flag is actually used anywhere..?
1009 // 20011208 mortene.
1010 PRIVATE(this)->locateHighlighting = onoff;
1011 }
1012
1013 void
setColinearThreshold(int newval)1014 SoTransformerDragger::setColinearThreshold(int newval)
1015 {
1016 SoTransformerDraggerP::colinearThreshold = newval;
1017 }
1018
1019 int
getColinearThreshold(void)1020 SoTransformerDragger::getColinearThreshold(void)
1021 {
1022 return SoTransformerDraggerP::colinearThreshold;
1023 }
1024
1025 SbVec3f
getBoxPointInWorldSpace(const SbVec3f & pointonunitbox)1026 SoTransformerDragger::getBoxPointInWorldSpace(const SbVec3f & pointonunitbox)
1027 {
1028 SbMatrix mat, inv;
1029 this->getSurroundScaleMatrices(mat, inv);
1030 mat.multRight(this->getLocalToWorldMatrix());
1031 SbVec3f ret;
1032 mat.multVecMatrix(pointonunitbox, ret);
1033 return ret;
1034 }
1035
1036 SbVec3f
getBoxDirInWorldSpace(const SbVec3f & dironunitbox)1037 SoTransformerDragger::getBoxDirInWorldSpace(const SbVec3f & dironunitbox)
1038 {
1039 SbMatrix mat, inv;
1040 this->getSurroundScaleMatrices(mat, inv);
1041 mat.multRight(this->getLocalToWorldMatrix());
1042 SbVec3f ret;
1043 mat.multDirMatrix(dironunitbox, ret);
1044 return ret;
1045 }
1046
1047 SbVec3f
getWorldPointInBoxSpace(const SbVec3f & pointinworldspace)1048 SoTransformerDragger::getWorldPointInBoxSpace(const SbVec3f & pointinworldspace)
1049 {
1050 SbMatrix mat, inv;
1051 this->getSurroundScaleMatrices(mat, inv);
1052 mat.multLeft(this->getWorldToLocalMatrix());
1053 SbVec3f ret;
1054 mat.multVecMatrix(pointinworldspace, ret);
1055 return ret;
1056 }
1057
1058 SbVec2f
getWorldPointInPixelSpace(const SbVec3f & thepoint)1059 SoTransformerDragger::getWorldPointInPixelSpace(const SbVec3f & thepoint)
1060 {
1061 SbVec3f screenpt;
1062 this->getViewVolume().projectToScreen(thepoint, screenpt);
1063 return SbVec2f(screenpt[0], screenpt[1]);
1064 }
1065
1066 SbVec3f
getInteractiveCenterInBoxSpace(void)1067 SoTransformerDragger::getInteractiveCenterInBoxSpace(void)
1068 {
1069 if (PRIVATE(this)->ctrlDown) return PRIVATE(this)->ctrlOffset;
1070 else return SbVec3f(0.0f, 0.0f, 0.0f);
1071 }
1072
1073 /*! \COININTERNAL */
1074 void
startCB(void *,SoDragger * d)1075 SoTransformerDragger::startCB(void *, SoDragger * d)
1076 {
1077 SoTransformerDragger * thisp = THISP(d);
1078 thisp->dragStart();
1079 }
1080
1081 /*! \COININTERNAL */
1082 void
motionCB(void *,SoDragger * d)1083 SoTransformerDragger::motionCB(void *, SoDragger * d)
1084 {
1085 SoTransformerDragger * thisp = THISP(d);
1086 thisp->drag();
1087 }
1088
1089 /*! \COININTERNAL */
1090 void
finishCB(void *,SoDragger * d)1091 SoTransformerDragger::finishCB(void *, SoDragger * d)
1092 {
1093 SoTransformerDragger * thisp = THISP(d);
1094 thisp->dragFinish();
1095 }
1096
1097 /*! \COININTERNAL */
1098 void
metaKeyChangeCB(void *,SoDragger * d)1099 SoTransformerDragger::metaKeyChangeCB(void *, SoDragger *d)
1100 {
1101 SoTransformerDragger * thisp = THISP(d);
1102 if (!thisp->isActive.getValue()) return;
1103
1104 const SoEvent *event = thisp->getEvent();
1105 if (PRIVATE(thisp)->shiftDown != event->wasShiftDown()) {
1106 thisp->drag();
1107 }
1108 if (PRIVATE(thisp)->ctrlDown != event->wasCtrlDown()) {
1109 thisp->drag();
1110 }
1111 }
1112
1113 // invalidate surround scale node, if it exists
1114 static void
invalidate_surroundscale(SoBaseKit * kit)1115 invalidate_surroundscale(SoBaseKit * kit)
1116 {
1117 SoSurroundScale * ss = coin_safe_cast<SoSurroundScale *>(
1118 kit->getPart("surroundScale", FALSE)
1119 );
1120 if (ss) ss->invalidate();
1121 }
1122
1123 /*! \COININTERNAL
1124 Called when dragger is selected (picked) by the user.
1125 */
1126 void
dragStart(void)1127 SoTransformerDragger::dragStart(void)
1128 {
1129 invalidate_surroundscale(this);
1130
1131 int i;
1132 const SoPath *pickpath = this->getPickPath();
1133 const SoEvent *event = this->getEvent();
1134
1135 SbBool found = FALSE;
1136 this->state = INACTIVE;
1137
1138 SbVec3f startpt = this->getLocalStartingPoint();
1139 startpt = this->localToWorking(startpt);
1140
1141 SbString str;
1142 if (!found) {
1143 for (i = 1; i <= 6; i++) {
1144 str.sprintf("translator%d", i);
1145 if (pickpath->findNode(this->getNodeFieldNode(str.getString())) >= 0 ||
1146 this->getSurrogatePartPickedName() == str.getString()) break;
1147 }
1148 if (i <= 6) {
1149 found = TRUE;
1150 this->state = static_cast<State>((int(RIT_TRANSLATE) + (i-1)));
1151 PRIVATE(this)->whatkind = WHATKIND_TRANSLATE;
1152 PRIVATE(this)->whatnum = i;
1153 if (i <= 2) PRIVATE(this)->dimension = 1;
1154 else if (i <= 4) PRIVATE(this)->dimension = 0;
1155 else PRIVATE(this)->dimension = 2;
1156 }
1157 }
1158
1159 if (!found) {
1160 for (i = 1; i <= 6; i++) {
1161 str.sprintf("rotator%d", i);
1162 if (pickpath->findNode(this->getNodeFieldNode(str.getString()))>= 0 ||
1163 this->getSurrogatePartPickedName() == str.getString()) break;
1164 }
1165 if (i <= 6) {
1166 found = TRUE;
1167 this->state = static_cast<State>((int(RIT_X_ROTATE) + (i-1)));
1168 PRIVATE(this)->whatkind = WHATKIND_ROTATE;
1169 PRIVATE(this)->whatnum = i;
1170 if (i <= 2) PRIVATE(this)->dimension = 1;
1171 else if (i <= 4) PRIVATE(this)->dimension = 0;
1172 else PRIVATE(this)->dimension = 2;
1173 }
1174 }
1175 if (!found) {
1176 for (i = 1; i <= 8; i++) {
1177 str.sprintf("scale%d", i);
1178 if (pickpath->findNode(this->getNodeFieldNode(str.getString()))>= 0 ||
1179 this->getSurrogatePartPickedName() == str.getString()) break;
1180 }
1181 if (i <= 8) {
1182 found = TRUE;
1183 this->state = static_cast<State>((int(PX_PY_PZ_3D_SCALE) + (i-1)));
1184 PRIVATE(this)->whatkind = WHATKIND_SCALE;
1185 PRIVATE(this)->whatnum = i;
1186 }
1187 }
1188 assert(found);
1189
1190 PRIVATE(this)->ctrlDown = event->wasCtrlDown();
1191 PRIVATE(this)->shiftDown = event->wasShiftDown();
1192 PRIVATE(this)->ctrlOffset = this->calcCtrlOffset(startpt);
1193
1194 switch(PRIVATE(this)->whatkind) {
1195 case WHATKIND_TRANSLATE:
1196 {
1197 SbVec3f n(0.0f, 0.0f, 0.0f);
1198 n[PRIVATE(this)->dimension] = 1.0f;
1199 this->planeProj->setPlane(SbPlane(n, startpt));
1200 this->lineProj->setLine(SbLine(startpt, startpt + n));
1201 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1202 if (PRIVATE(this)->shiftDown) {
1203 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1204 }
1205 SbLine myline(SbVec3f(0.0f, 0.0f, 0.0f), n);
1206 SoTranslation *t = SO_GET_ANY_PART(this, "axisFeedbackLocation", SoTranslation);
1207 t->translation = myline.getClosestPoint(startpt);
1208
1209 this->setAllPartSwitches(SO_SWITCH_NONE, SO_SWITCH_NONE, SO_SWITCH_NONE);
1210 str.sprintf("translator%dSwitch", PRIVATE(this)->whatnum);
1211 this->setSwitchValue(str.getString(), 1);
1212 this->setSwitchValue("translateBoxFeedbackSwitch", SO_SWITCH_ALL);
1213 SoRotation * feedbackrot = coin_assert_cast<SoRotation *>(this->getAnyPart("translateBoxFeedbackRotation", TRUE));
1214 assert(feedbackrot);
1215 switch (PRIVATE(this)->whatnum) {
1216 default:
1217 case 1:
1218 feedbackrot->rotation = SbRotation::identity();
1219 break;
1220 case 2:
1221 feedbackrot->rotation = SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), float(M_PI));
1222 break;
1223 case 3:
1224 feedbackrot->rotation = SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), float(M_PI)*0.5f);
1225 break;
1226 case 4:
1227 feedbackrot->rotation = SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), -float(M_PI)*0.5f);
1228 break;
1229 case 5:
1230 feedbackrot->rotation = SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), float(M_PI)*0.5f);
1231 break;
1232 case 6:
1233 feedbackrot->rotation = SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), -float(M_PI)*0.5f);
1234 break;
1235 }
1236 (void) this->setDynamicTranslatorSwitches(event);
1237 }
1238 break;
1239 case WHATKIND_SCALE:
1240 {
1241 SoTranslation *t = SO_GET_ANY_PART(this, "axisFeedbackLocation", SoTranslation);
1242 t->translation = startpt;
1243 this->lineProj->setLine(SbLine(SbVec3f(0.0f, 0.0f, 0.0f), startpt));
1244 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1245 if (PRIVATE(this)->shiftDown) {
1246 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1247 }
1248
1249 str.sprintf("scale%dSwitch", PRIVATE(this)->whatnum);
1250 this->setAllPartSwitches(0, SO_SWITCH_NONE, SO_SWITCH_NONE);
1251 this->setSwitchValue(str.getString(), 1);
1252 (void) this->setDynamicScaleSwitches(event);
1253 }
1254 break;
1255 case WHATKIND_ROTATE:
1256 {
1257 SoTranslation *t = SO_GET_ANY_PART(this, "axisFeedbackLocation", SoTranslation);
1258 t->translation = startpt;
1259 this->sphereProj->setSphere(SbSphere(SbVec3f(0.0f, 0.0f, 0.0f), startpt.length()));
1260 this->sphereProj->setViewVolume(this->getViewVolume());
1261 this->sphereProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1262
1263 switch (this->getFrontOnProjector()) {
1264 case FRONT:
1265 this->sphereProj->setFront(TRUE);
1266 break;
1267 case BACK:
1268 this->sphereProj->setFront(TRUE);
1269 break;
1270 default: // avoid warnings
1271 case USE_PICK:
1272 this->sphereProj->setFront(this->sphereProj->isPointInFront(startpt));
1273 break;
1274 }
1275
1276 SbVec3f projpt = this->sphereProj->project(this->getNormalizedLocaterPosition());
1277 this->getWorkingToWorldMatrix().multVecMatrix(projpt, PRIVATE(this)->prevWorldHitPt);
1278 PRIVATE(this)->prevMotionMatrix = this->getMotionMatrix();
1279
1280 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1281 if (!PRIVATE(this)->shiftDown) {
1282 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1283 // this plane is only used to find constraint direction
1284 this->planeProj->setPlane(SbPlane(startpt, startpt));
1285 PRIVATE(this)->normalizedStartLocaterPosition = this->getNormalizedLocaterPosition();
1286 }
1287 SoAntiSquish *squish = SO_GET_ANY_PART(this, "circleFeedbackAntiSquish", SoAntiSquish);
1288 SoAntiSquish::Sizing sizing;
1289 switch (PRIVATE(this)->dimension) {
1290 case 0: sizing = SoAntiSquish::X; break;
1291 case 1: sizing = SoAntiSquish::Y; break;
1292 case 2: sizing = SoAntiSquish::Z; break;
1293 default: assert(FALSE); sizing = SoAntiSquish::Z; // Dummy assignment to avoid compiler warning.
1294 }
1295 squish->sizing = sizing;
1296 squish->recalc();
1297 this->setAllPartSwitches(SO_SWITCH_NONE, 0, SO_SWITCH_NONE);
1298 (void) this->setDynamicRotatorSwitches(event);
1299 }
1300 break;
1301 default:
1302 assert(0 && "unknown whatkind");
1303 break;
1304 }
1305 }
1306
1307 /*! \COININTERNAL
1308 Called when user drags the mouse after picking the dragger.
1309 */
1310 void
drag(void)1311 SoTransformerDragger::drag(void)
1312 {
1313 switch(PRIVATE(this)->whatkind) {
1314 case WHATKIND_SCALE:
1315 this->dragScale();
1316 break;
1317 case WHATKIND_TRANSLATE:
1318 this->dragTranslate();
1319 break;
1320 case WHATKIND_ROTATE:
1321 this->dragRotate();
1322 break;
1323 default:
1324 assert(0 && "illegal whatkind");
1325 break;
1326 }
1327 }
1328
1329 void
dragTranslate()1330 SoTransformerDragger::dragTranslate()
1331 {
1332 SbVec3f startpt = this->getLocalStartingPoint();
1333 startpt = this->localToWorking(startpt);
1334
1335 this->planeProj->setViewVolume(this->getViewVolume());
1336 this->planeProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1337 SbVec3f projpt = this->planeProj->project(this->getNormalizedLocaterPosition());
1338
1339 const SoEvent *event = this->getEvent();
1340 if (event->wasShiftDown() && PRIVATE(this)->constraintState == CONSTRAINT_OFF) {
1341 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1342 this->setStartLocaterPosition(event->getPosition());
1343 }
1344 else if (!event->wasShiftDown() && PRIVATE(this)->constraintState != CONSTRAINT_OFF) {
1345 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1346 }
1347
1348 // Every time something changes (shift or ctrl is pressed), resave
1349 // the state so that the transformation to come starts with blank
1350 // sheets.
1351 if (this->setDynamicTranslatorSwitches(event)) {
1352 this->saveStartParameters();
1353 SbVec3f n(0.0f, 0.0f, 0.0f);
1354 n[PRIVATE(this)->dimension] = 1.0f;
1355 this->lineProj->setLine(SbLine(projpt, projpt+n));
1356 SbVec3f worldpt;
1357 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldpt);
1358 this->setStartingPoint(worldpt);
1359 startpt = projpt;
1360 }
1361
1362 SbVec3f motion;
1363 if (PRIVATE(this)->ctrlDown) {
1364 this->lineProj->setViewVolume(this->getViewVolume());
1365 this->lineProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1366 projpt = this->lineProj->project(this->getNormalizedLocaterPosition());
1367 motion = projpt - startpt;
1368 }
1369 else {
1370 motion = projpt - startpt;
1371
1372 switch(PRIVATE(this)->constraintState) {
1373 case CONSTRAINT_OFF:
1374 break;
1375 case CONSTRAINT_WAIT:
1376 if (this->isAdequateConstraintMotion()) {
1377 int biggest = 0;
1378 double bigval = fabs(motion[0]);
1379 if (fabs(motion[1]) > bigval) {
1380 biggest = 1;
1381 bigval = fabs(motion[1]);
1382 }
1383 if (fabs(motion[2]) > bigval) {
1384 biggest = 2;
1385 }
1386
1387 // Set all but the constraint axis to 0
1388 motion[(biggest + 1) % 3] = 0.0f;
1389 motion[(biggest + 2) % 3] = 0.0f;
1390
1391 PRIVATE(this)->constraintState = CONSTRAINT_X + biggest;
1392 }
1393 else {
1394 return;
1395 }
1396 break;
1397 case CONSTRAINT_X:
1398 motion[1] = 0.0f;
1399 motion[2] = 0.0f;
1400 break;
1401 case CONSTRAINT_Y:
1402 motion[0] = 0.0f;
1403 motion[2] = 0.0f;
1404 break;
1405 case CONSTRAINT_Z:
1406 motion[0] = 0.0f;
1407 motion[1] = 0.0f;
1408 break;
1409 }
1410 }
1411
1412 SbMatrix mat, inv;
1413 this->getSurroundScaleMatrices(mat, inv);
1414 this->setMotionMatrix(this->appendTranslation(this->getStartMotionMatrix(), motion, &mat));
1415 this->unsquishKnobs();
1416 }
1417
1418 void
dragScale()1419 SoTransformerDragger::dragScale()
1420 {
1421 SbVec3f startpt = this->getLocalStartingPoint();
1422 startpt = this->localToWorking(startpt);
1423
1424 this->lineProj->setViewVolume(this->getViewVolume());
1425 this->lineProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1426 SbVec3f projpt = this->lineProj->project(this->getNormalizedLocaterPosition());
1427 const SoEvent *event = this->getEvent();
1428
1429 if (event->wasShiftDown() && PRIVATE(this)->constraintState == CONSTRAINT_OFF) {
1430 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1431 this->setStartLocaterPosition(event->getPosition());
1432 }
1433 else if (!event->wasShiftDown() && PRIVATE(this)->constraintState != CONSTRAINT_OFF) {
1434 this->saveStartParameters();
1435 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1436 this->lineProj->setLine(SbLine(SbVec3f(0.0f, 0.0f, 0.0f), projpt));
1437 PRIVATE(this)->ctrlOffset = this->calcCtrlOffset(projpt);
1438 startpt = projpt;
1439 SbVec3f worldpt;
1440 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldpt);
1441 this->setStartingPoint(worldpt);
1442 }
1443
1444 if (PRIVATE(this)->constraintState == CONSTRAINT_WAIT && this->isAdequateConstraintMotion()) {
1445 // detect which dimension user has moved mouse the most. Done by projecting
1446 // mouse positions onto the near plane, finding that world vector, and
1447 // transforming that world vector into working space.
1448 const SbViewVolume &vv = this->getViewVolume();
1449 const SbViewportRegion &vp = this->getViewportRegion();
1450 SbVec2s move = this->getLocaterPosition() - this->getStartLocaterPosition();
1451 SbVec2f normmove(
1452 static_cast<float>(move[0])/static_cast<float>(vp.getViewportSizePixels()[0]),
1453 static_cast<float>(move[1])/static_cast<float>(vp.getViewportSizePixels()[1])
1454 );
1455 SbVec3f tmp = vv.getPlanePoint(vv.getNearDist(), SbVec2f(0.5f, 0.5f));
1456 SbVec3f dir = vv.getPlanePoint(vv.getNearDist(), SbVec2f(0.5f, 0.5f) + normmove);
1457 dir -= tmp;
1458 (void) dir.normalize(); // ok if null (no movement)
1459 this->getWorldToWorkingMatrix().multDirMatrix(dir, dir);
1460 int biggest = 0;
1461 double bigval = fabs(dir[0]);
1462 if (fabs(dir[1]) > bigval) {
1463 biggest = 1;
1464 bigval = fabs(dir[1]);
1465 }
1466 if (fabs(dir[2]) > bigval) {
1467 biggest = 2;
1468 }
1469 SbVec3f n(0.0f, 0.0f, 0.0f);
1470 n[biggest] = 1.0f;
1471
1472 PRIVATE(this)->constraintState = CONSTRAINT_X + biggest;
1473
1474 this->saveStartParameters();
1475 this->lineProj->setLine(SbLine(projpt, projpt+n));
1476 startpt = projpt;
1477 projpt[(biggest+1)%3] = 0.0f;
1478 projpt[(biggest+2)%3] = 0.0f;
1479 PRIVATE(this)->ctrlOffset = this->calcCtrlOffset(projpt);
1480 projpt = startpt;
1481 SbVec3f worldpt;
1482 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldpt);
1483 this->setStartingPoint(worldpt);
1484 }
1485
1486 // If the control key is pressed or released,
1487 // setDynamicScaleSwitches will return TRUE. When this happens, we
1488 // have to resave our start motionmatrix to be able to do correct
1489 // scaling. If we do not do this, the scaled object will jump
1490 // because the scale center is changed, but not the scale.
1491 if (this->setDynamicScaleSwitches(event)) {
1492 this->saveStartParameters();
1493 startpt = projpt;
1494
1495 SbVec3f worldpt;
1496 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldpt);
1497 this->setStartingPoint(worldpt);
1498 }
1499
1500 if (PRIVATE(this)->constraintState == CONSTRAINT_WAIT) return;
1501
1502 if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
1503 int num = PRIVATE(this)->constraintState - CONSTRAINT_X;
1504 projpt[(num+1)%3] = 0.0f;
1505 projpt[(num+2)%3] = 0.0f;
1506 startpt[(num+1)%3] = 0.0f;
1507 startpt[(num+2)%3] = 0.0f;
1508 }
1509
1510 SbVec3f center(0.0f, 0.0f, 0.0f);
1511 if (PRIVATE(this)->ctrlDown) {
1512 center -= PRIVATE(this)->ctrlOffset;
1513 }
1514
1515 float orglen = (startpt-center).length();
1516 float currlen = (projpt-center).length();
1517 float scale = 0.0f;
1518
1519 if (orglen > 0.0f) scale = currlen / orglen;
1520 if (scale > 0.0f && (startpt-center).dot(projpt-center) <= 0.0f) scale = 0.0f;
1521
1522 SbVec3f scalevec(scale, scale, scale);
1523 if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
1524 int num = PRIVATE(this)->constraintState - CONSTRAINT_X;
1525 scalevec[(num+1)%3] = 1.0f;
1526 scalevec[(num+2)%3] = 1.0f;
1527 }
1528
1529 SbMatrix mat, inv;
1530 this->getSurroundScaleMatrices(mat, inv);
1531 this->setMotionMatrix(this->appendScale(this->getStartMotionMatrix(),
1532 scalevec,
1533 center, &mat));
1534 this->unsquishKnobs();
1535 }
1536
1537 // The dragRotate method has been implemented somewhat differently
1538 // than the other drag functions. This is because of the unfortunate
1539 // effect that happens when a non-uniform scale has been applied to
1540 // the motion-matrix, and rotation is attempted to be done before the
1541 // scale. Both operations are perfectly valid, but the end result is
1542 // not what you'd expect; the transformation comes out sheared. To
1543 // prevent this from happening, the rotation matrices are applied in
1544 // world space, that is after all other transformations have been
1545 // applied (scale and translation are applied in local
1546 // space). What is basically done is this:
1547 //
1548 // Calculates the matrix (as done in SoDragger::appendRotation()):
1549 //
1550 // C := conversion
1551 // P := rotcenter
1552 // R := rot
1553 // M := new motion matrix
1554 // Mold := previous motionmatrix
1555 //
1556 // M = C^-1 * P^-1 * R * P * C * Mold
1557 //
1558 // What essentially happens is that we transform into C's coordinate
1559 // system, then we move the rotation center to origo and apply the
1560 // new rotation. The rotation has now been applied, but we are in
1561 // the wrong coordinate system, so we reapply the rotation center
1562 // and the conversion. Finally we transform the matrix by the old
1563 // transformation, which gives us the new rotated transformation.
1564 //
1565 // The rotation happens in the local coordinate system of the object
1566 // if C = P = I, but if P is specified, then the rotation center
1567 // will be adjusted before the rotation is applied. If the
1568 // conversion matrix has been specified to be e.g:
1569 //
1570 // C = (Mold * W)^-1
1571 //
1572 // Then the resulting matrix looks something like this:
1573 //
1574 // M = ((Mold * W)^-1)^-1 * P^-1 * R * P * (Mold * W)^-1 * Mold
1575 // = Mold * W * P^-1 * R * P * W^-1 * Mold^-1 * Mold
1576 // = Mold * W * P^-1 * R * P * W^-1
1577 //
1578 // Take a closer look at the resulting matrix: It basically reverses
1579 // the transformation. Instead of having the rotation applied before
1580 // the old transformation, the rotation is applied after the old
1581 // transformation. The rotation also happens in world space - that is
1582 // the coordinate system is transformed to the world coordinate system
1583 // before the rotation is applied around rotationcenter. Finally the
1584 // matrix is transformed back to the local coordinate system.
1585 void
dragRotate(void)1586 SoTransformerDragger::dragRotate(void)
1587 {
1588 // Update the sphere projector to the current view so that it
1589 // accurately can react to events.
1590 this->sphereProj->setViewVolume(this->getViewVolume());
1591 this->sphereProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1592
1593 const SoEvent *event = this->getEvent();
1594
1595 SbVec3f startpt, projpt;
1596 startpt = this->getLocalStartingPoint();
1597 startpt = this->localToWorking(startpt);
1598
1599 // If shift was pressed and not in non-constrained state, then
1600 // we switch to non-constrained state.
1601 if (event->wasShiftDown() && PRIVATE(this)->constraintState != CONSTRAINT_OFF) {
1602 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1603 projpt = this->sphereProj->project(this->getNormalizedLocaterPosition());
1604 this->getWorkingToWorldMatrix().multVecMatrix(projpt, PRIVATE(this)->prevWorldHitPt);
1605 PRIVATE(this)->prevMotionMatrix = this->getMotionMatrix();
1606 this->saveStartParameters();
1607 this->setStartingPoint(PRIVATE(this)->prevWorldHitPt);
1608 }
1609 // If shift was released while in non-constrained state, then the
1610 // state jumps back to constrained.
1611 else if (!event->wasShiftDown() && PRIVATE(this)->constraintState == CONSTRAINT_OFF) {
1612 PRIVATE(this)->constraintState = CONSTRAINT_WAIT;
1613 this->setStartingPoint(PRIVATE(this)->prevWorldHitPt);
1614 startpt = this->getLocalStartingPoint();
1615 startpt = this->localToWorking(startpt);
1616 // This plane is only used to find the constraint direction
1617 this->planeProj->setPlane(SbPlane(startpt, startpt));
1618 this->setStartLocaterPosition(event->getPosition());
1619 PRIVATE(this)->normalizedStartLocaterPosition = this->getNormalizedLocaterPosition();
1620 this->saveStartParameters();
1621 }
1622
1623 SbVec3f center(0.0f, 0.0f, 0.0f);
1624 if (PRIVATE(this)->ctrlDown) {
1625 // Adjust the center to be on the other side of the bounding box
1626 // when the control key has been pressed.
1627 center -= PRIVATE(this)->ctrlOffset * KNOB_DISTANCE;
1628 }
1629
1630 // Show the necessary feedback geometry for rotation.
1631 (void) this->setDynamicRotatorSwitches(event);
1632
1633 if (PRIVATE(this)->constraintState == CONSTRAINT_OFF) {
1634 SbVec3f worldcenter = this->getBoxPointInWorldSpace(center);
1635 SbVec3f prevworldprojpt = PRIVATE(this)->prevWorldHitPt;
1636 SbVec3f worldprojpt;
1637
1638 // Find locater position in world space
1639 projpt = this->sphereProj->project(this->getNormalizedLocaterPosition());
1640 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldprojpt);
1641 SbVec3f wppt = worldprojpt;
1642
1643 // Find the projection vectors from the box center in world space.
1644 worldprojpt -= worldcenter;
1645 prevworldprojpt -= worldcenter;
1646
1647 // FIXME: Without this test, the rotation behaves very strange,
1648 // especially at the edge/outside of the sphere. I will
1649 // investigate this some more to understand what happens.
1650 // 20040804 jornskaa
1651
1652 // Normalize the vectors before finding the dotproduct angle
1653 // between them.
1654 if ((worldprojpt.normalize() > 0.0f) &&
1655 (prevworldprojpt.normalize() > 0.0f) &&
1656 (worldprojpt.dot(prevworldprojpt) > 0.8f)) {
1657 PRIVATE(this)->prevWorldHitPt = wppt;
1658
1659 // Calculate the rotation from previous prevworldprojpt to
1660 // worldprojpt
1661 SbRotation rot(prevworldprojpt, worldprojpt);
1662
1663 // Calculate new motionmatrix by rotating in world space to
1664 // prevent shearing with non-uniform scale.
1665 SbMatrix mat = this->getWorldToLocalMatrix();
1666 PRIVATE(this)->prevMotionMatrix = this->appendRotation(PRIVATE(this)->prevMotionMatrix, rot,
1667 worldcenter, &mat);
1668
1669 this->setMotionMatrix(PRIVATE(this)->prevMotionMatrix);
1670 }
1671 }
1672 else if (PRIVATE(this)->constraintState == CONSTRAINT_WAIT && this->isAdequateConstraintMotion()) {
1673 this->planeProj->setViewVolume(this->getViewVolume());
1674 this->planeProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1675 projpt = this->planeProj->project(this->getNormalizedLocaterPosition());
1676
1677 SbVec3f diff = projpt - startpt;
1678 diff[PRIVATE(this)->dimension] = 0.0f;
1679
1680 int biggest = 0;
1681 double bigval = fabs(diff[0]);
1682 if (fabs(diff[1]) > bigval) {
1683 biggest = 1;
1684 bigval = fabs(diff[1]);
1685 }
1686 if (fabs(diff[2]) > bigval) {
1687 biggest = 2;
1688 }
1689 PRIVATE(this)->constraintState = CONSTRAINT_X + biggest;
1690 SbVec3f n(0.0f, 0.0f, 0.0f);
1691 n[biggest] = 1.0f;
1692 SbVec3f dim(0.0f, 0.0f, 0.0f);
1693 dim[PRIVATE(this)->dimension] = 1.0f;
1694
1695 // set plane to do disc-rotate in
1696 this->planeProj->setPlane(SbPlane(SbVec3f(0.0f, 0.0f, 0.0f), dim, dim+n));
1697 (void) this->setDynamicRotatorSwitches(event);
1698
1699 // Initialize prevWorldHitPt and prevMotionMatrix.
1700 projpt = this->planeProj->project(PRIVATE(this)->normalizedStartLocaterPosition);
1701 this->getWorkingToWorldMatrix().multVecMatrix(projpt, PRIVATE(this)->prevWorldHitPt);
1702 PRIVATE(this)->prevMotionMatrix = this->getMotionMatrix();
1703 }
1704 if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
1705 this->planeProj->setViewVolume(this->getViewVolume());
1706 this->planeProj->setWorkingSpace(this->getWorkingToWorldMatrix());
1707
1708 SbVec3f worldcenter = this->getBoxPointInWorldSpace(center);
1709 SbVec3f prevworldprojpt;
1710 SbVec3f prevprojpt;
1711 SbVec3f worldprojpt;
1712
1713 prevworldprojpt = PRIVATE(this)->prevWorldHitPt;
1714
1715 // Find current locater position projected onto the plane in world
1716 // space.
1717 projpt = this->planeProj->project(this->getNormalizedLocaterPosition());
1718 this->getWorkingToWorldMatrix().multVecMatrix(projpt, worldprojpt);
1719
1720 // Project the vectors onto the projection plane in world space.
1721 // This is needed to make the rotation vectors more numerically
1722 // stable especially when the dragger has been scaled to be very
1723 // small before rotation is attempted.
1724 SbPlane plane = this->planeProj->getPlane();
1725 plane.transform(this->getWorkingToWorldMatrix());
1726 prevworldprojpt -= plane.getNormal() * plane.getDistance(prevworldprojpt);
1727 worldprojpt -= plane.getNormal() * plane.getDistance(worldprojpt);
1728
1729 // Save the values for the new projection point before it is
1730 // altered.
1731 SbVec3f wppt = worldprojpt;
1732
1733 // Adjust the rotation vectors of the dragger to match the center
1734 // of the dragger in working space and world space.
1735 projpt -= center;
1736 prevworldprojpt -= worldcenter;
1737 worldprojpt -= worldcenter;
1738
1739 // Make sure the length of the projected vector is greater than
1740 // a scalar constant. This ensures that the rotation is defined
1741 // and there is little room for error that might happen when the
1742 // vectors come very close to the rotation center.
1743 if (projpt.sqrLength() > 0.1f) {
1744 // Since we are using incremental changes, the changes will
1745 // never be very big, and the dot product between the
1746 // rotation-vectors should always be above zero, and never
1747 // negative because that indicates the angle between the vectors
1748 // is above PI/2. This might happen if dragging is done over the
1749 // rotation center, but we do not allow that and just wait until
1750 // the locater comes into the valid range before rotating.
1751
1752 // Normalize the vectors before finding the dotproduct angle
1753 // between them.
1754 if ((prevworldprojpt.normalize() > 0.0f) &&
1755 (worldprojpt.normalize() > 0.0f) &&
1756 (prevworldprojpt.dot(worldprojpt) > 0.3f)) { // 0.3 == 72.5degrees
1757 PRIVATE(this)->prevWorldHitPt = wppt;
1758
1759 // Rotate between the two points in the plane
1760 SbRotation rot(prevworldprojpt, worldprojpt);
1761
1762 // Rotate in world space to prevent shearing when having
1763 // non-uniform scale.
1764 SbMatrix mat = this->getWorldToLocalMatrix();
1765 PRIVATE(this)->prevMotionMatrix = (this->appendRotation(PRIVATE(this)->prevMotionMatrix, rot,
1766 worldcenter, &mat));
1767
1768 this->setMotionMatrix(PRIVATE(this)->prevMotionMatrix);
1769 }
1770 }
1771 }
1772 this->unsquishKnobs();
1773 }
1774
1775 /*! \COININTERNAL
1776 Called when mouse button is released after picking and interacting
1777 with the dragger.
1778 */
1779 void
dragFinish(void)1780 SoTransformerDragger::dragFinish(void)
1781 {
1782 switch (PRIVATE(this)->whatkind) {
1783 case WHATKIND_TRANSLATE:
1784 this->setSwitchValue("translateBoxFeedbackSwitch", SO_SWITCH_NONE);
1785 break;
1786 case WHATKIND_ROTATE:
1787 this->setSwitchValue("xCircleFeedbackSwitch", SO_SWITCH_NONE);
1788 this->setSwitchValue("yCircleFeedbackSwitch", SO_SWITCH_NONE);
1789 this->setSwitchValue("zCircleFeedbackSwitch", SO_SWITCH_NONE);
1790 break;
1791 case WHATKIND_SCALE:
1792 this->setSwitchValue("radialFeedbackSwitch", SO_SWITCH_NONE);
1793 this->setSwitchValue("posXWallFeedbackSwitch", SO_SWITCH_NONE);
1794 this->setSwitchValue("negXWallFeedbackSwitch", SO_SWITCH_NONE);
1795 this->setSwitchValue("posYWallFeedbackSwitch", SO_SWITCH_NONE);
1796 this->setSwitchValue("negYWallFeedbackSwitch", SO_SWITCH_NONE);
1797 this->setSwitchValue("posZWallFeedbackSwitch", SO_SWITCH_NONE);
1798 this->setSwitchValue("negZWallFeedbackSwitch", SO_SWITCH_NONE);
1799 this->setSwitchValue("scaleBoxFeedbackSwitch", SO_SWITCH_NONE);
1800 break;
1801 default:
1802 assert(0 && "unknown whatkind");
1803 break;
1804 }
1805
1806 PRIVATE(this)->whatkind = WHATKIND_NONE;
1807 this->state = INACTIVE;
1808 PRIVATE(this)->constraintState = CONSTRAINT_OFF;
1809 this->setAllPartSwitches(0,0,0);
1810 this->setSwitchValue("xAxisFeedbackSwitch", SO_SWITCH_NONE);
1811 this->setSwitchValue("yAxisFeedbackSwitch", SO_SWITCH_NONE);
1812 this->setSwitchValue("zAxisFeedbackSwitch", SO_SWITCH_NONE);
1813
1814 #if COIN_DEBUG && 0 // used to debug motion matrix (pederb, 20000225)
1815 SbMatrix m = this->getMotionMatrix();
1816 SbRotation r,so;
1817 SbVec3f t,s;
1818
1819 fprintf(stderr,"motion matrix:\n");
1820 m.print(stderr);
1821 m.getTransform(t, r, s, so);
1822 SbVec3f rx, sox;
1823 float ra, soa;
1824 r.getValue(rx, ra);
1825 so.getValue(sox, soa);
1826 fprintf(stderr,
1827 "\nt: %g %g %g\n"
1828 "r: %g %g %g, %g\n"
1829 "s: %g %g %g\n"
1830 "so: %g %g %g, %g\n\n",
1831 t[0], t[1], t[2],
1832 rx[0], rx[1], rx[2], ra,
1833 s[0], s[1], s[2],
1834 sox[0], sox[1], sox[2], soa);
1835 #endif // debug code
1836 invalidate_surroundscale(this);
1837 }
1838
1839 void
updateAntiSquishList(void)1840 SoTransformerDragger::updateAntiSquishList(void)
1841 {
1842 if (this->antiSquishList.getLength() == 0) {
1843 SoSeparator *top = SO_GET_ANY_PART(this, "topSeparator", SoSeparator);
1844 assert(top);
1845
1846 SoSearchAction sa;
1847 sa.setInterest(SoSearchAction::ALL);
1848 sa.setType(SoAntiSquish::getClassTypeId());
1849 sa.setSearchingAll(TRUE);
1850 sa.apply(top);
1851
1852 SoPathList &pl = sa.getPaths();
1853 for (int i = 0; i < pl.getLength(); i++) {
1854 SoFullPath * path = reclassify_cast<SoFullPath *>(pl[i]);
1855 SoNode * tail = path->getTail();
1856 int j, n = this->antiSquishList.getLength();
1857 for (j = 0; j < n; j++) {
1858 if (this->antiSquishList[j] == tail) break;
1859 }
1860 if (j == n)
1861 this->antiSquishList.append(path->getTail());
1862 }
1863 }
1864 int n = this->antiSquishList.getLength();
1865 for (int i = 0; i < n; i++) {
1866 SoAntiSquish * squishy = coin_assert_cast<SoAntiSquish *>(this->antiSquishList[i]);
1867 squishy->recalc();
1868 }
1869 }
1870
1871 void
setAllPartSwitches(int scalewhich,int rotatewhich,int translatewhich)1872 SoTransformerDragger::setAllPartSwitches(int scalewhich, int rotatewhich, int translatewhich)
1873 {
1874 int i;
1875 SoSwitch *sw;
1876 SbString str;
1877
1878 for (i = 1; i <= 6; i++) {
1879 str.sprintf("translator%dSwitch", i);
1880 sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
1881 SoInteractionKit::setSwitchValue(sw, translatewhich);
1882 }
1883 for (i = 1; i <= 6; i++) {
1884 str.sprintf("rotator%dSwitch", i);
1885 sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
1886 SoInteractionKit::setSwitchValue(sw, rotatewhich);
1887 }
1888 for (i = 1; i <= 8; i++) {
1889 str.sprintf("scale%dSwitch", i);
1890 sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
1891 SoInteractionKit::setSwitchValue(sw, scalewhich);
1892 }
1893 }
1894
1895 /*!
1896 Not implemented in Coin; should probably not have been public in the
1897 Open Inventor API. We'll consider to implement it if requested.
1898 */
1899 int
getMouseGestureDirection(SbBool COIN_UNUSED_ARG (x_ok),SbBool COIN_UNUSED_ARG (y_ok),SbBool COIN_UNUSED_ARG (z_ok))1900 SoTransformerDragger::getMouseGestureDirection(SbBool COIN_UNUSED_ARG(x_ok), SbBool COIN_UNUSED_ARG(y_ok), SbBool COIN_UNUSED_ARG(z_ok))
1901 {
1902 COIN_OBSOLETED();
1903 return -1;
1904 }
1905
1906 /*!
1907 Not implemented in Coin; should probably not have been public in the
1908 Open Inventor API. We'll consider to implement it if requested.
1909 */
1910 int
getIgnoreAxis(SbVec2f COIN_UNUSED_ARG (axis[3][2]),SbBool COIN_UNUSED_ARG (x_ok),SbBool COIN_UNUSED_ARG (y_ok),SbBool COIN_UNUSED_ARG (z_ok))1911 SoTransformerDragger::getIgnoreAxis(SbVec2f COIN_UNUSED_ARG(axis[3][2]), SbBool COIN_UNUSED_ARG(x_ok), SbBool COIN_UNUSED_ARG(y_ok), SbBool COIN_UNUSED_ARG(z_ok))
1912 {
1913 COIN_OBSOLETED();
1914 return -1;
1915 }
1916
1917 /*!
1918 Not implemented in Coin; should probably not have been public in the
1919 Open Inventor API. We'll consider to implement it if requested.
1920 */
1921 void
makeMinorAxisPerpendicularIfColinear(SbVec2f COIN_UNUSED_ARG (origin),SbVec2f COIN_UNUSED_ARG (axisends[3][2]),int COIN_UNUSED_ARG (index_a),int COIN_UNUSED_ARG (index_b))1922 SoTransformerDragger::makeMinorAxisPerpendicularIfColinear(SbVec2f COIN_UNUSED_ARG(origin), SbVec2f COIN_UNUSED_ARG(axisends[3][2]), int COIN_UNUSED_ARG(index_a), int COIN_UNUSED_ARG(index_b))
1923 {
1924 COIN_OBSOLETED();
1925 }
1926
1927 /*!
1928 Not implemented in Coin; should probably not have been public in the
1929 Open Inventor API. We'll consider to implement it if requested.
1930 */
1931 SbBool
isColinear(SbVec2f COIN_UNUSED_ARG (a1[2]),SbVec2f COIN_UNUSED_ARG (a2[2]),int COIN_UNUSED_ARG (pixels))1932 SoTransformerDragger::isColinear(SbVec2f COIN_UNUSED_ARG(a1[2]), SbVec2f COIN_UNUSED_ARG(a2[2]), int COIN_UNUSED_ARG(pixels))
1933 {
1934 COIN_OBSOLETED();
1935 return FALSE;
1936 }
1937
1938 void
getSurroundScaleMatrices(SbMatrix & mat,SbMatrix & inv)1939 SoTransformerDragger::getSurroundScaleMatrices(SbMatrix & mat, SbMatrix & inv)
1940 {
1941 if (this->surroundScale.getValue()) {
1942 this->getPartToLocalMatrix("surroundScale", mat, inv);
1943 }
1944 else {
1945 mat = inv = SbMatrix::identity();
1946 }
1947 }
1948
1949 SoNode *
getNodeFieldNode(const char * fieldname)1950 SoTransformerDragger::getNodeFieldNode(const char *fieldname)
1951 {
1952 SoField *field = this->getField(fieldname);
1953 assert(field != NULL);
1954 assert(field->isOfType(SoSFNode::getClassTypeId()));
1955 assert(coin_assert_cast<SoSFNode *>(field)->getValue() != NULL);
1956 return coin_assert_cast<SoSFNode *>(field)->getValue();
1957 }
1958
1959 SbMatrix
getWorkingToWorldMatrix()1960 SoTransformerDragger::getWorkingToWorldMatrix()
1961 {
1962 SbMatrix mat, inv;
1963 this->getSurroundScaleMatrices(mat, inv);
1964 mat.multRight(this->getLocalToWorldMatrix());
1965 return mat;
1966 }
1967
1968 SbMatrix
getWorldToWorkingMatrix(void)1969 SoTransformerDragger::getWorldToWorkingMatrix(void)
1970 {
1971 SbMatrix mat, inv;
1972 this->getSurroundScaleMatrices(mat, inv);
1973 mat.multLeft(this->getWorldToLocalMatrix());
1974 return mat;
1975 }
1976
1977 SbVec3f
localToWorking(const SbVec3f & v)1978 SoTransformerDragger::localToWorking(const SbVec3f &v)
1979 {
1980 SbMatrix mat, inv;
1981 this->getSurroundScaleMatrices(mat, inv);
1982 SbVec3f ret;
1983 inv.multVecMatrix(v, ret);
1984 return ret;
1985 }
1986
1987 SbVec3f
workingToLocal(const SbVec3f & v)1988 SoTransformerDragger::workingToLocal(const SbVec3f &v)
1989 {
1990 SbMatrix mat, inv;
1991 this->getSurroundScaleMatrices(mat, inv);
1992 SbVec3f ret;
1993 mat.multVecMatrix(v, ret);
1994 return ret;
1995 }
1996
1997 SbVec3f
calcCtrlOffset(const SbVec3f & startpt)1998 SoTransformerDragger::calcCtrlOffset(const SbVec3f &startpt)
1999 {
2000 SbVec3f v = startpt;
2001 for (int i = 0; i < 3; i++) {
2002 if (v[i] < -0.8) v[i] = -1.0f;
2003 else if (v[i] > 0.8) v[i] = 1.0f;
2004 else v[i] = 0.0f;
2005 }
2006 return v;
2007 }
2008
2009 void
setSwitchValue(const char * str,const int which)2010 SoTransformerDragger::setSwitchValue(const char *str, const int which)
2011 {
2012 SoSwitch *sw = SO_GET_ANY_PART(this, str, SoSwitch);
2013 SoInteractionKit::setSwitchValue(sw, which);
2014 }
2015
2016 SbBool
setDynamicTranslatorSwitches(const SoEvent * event)2017 SoTransformerDragger::setDynamicTranslatorSwitches(const SoEvent *event)
2018 {
2019 SbBool changed = FALSE;
2020 if (PRIVATE(this)->ctrlDown != event->wasCtrlDown()) {
2021 changed = TRUE;
2022 PRIVATE(this)->ctrlDown = !PRIVATE(this)->ctrlDown;
2023 }
2024 if (PRIVATE(this)->shiftDown != event->wasShiftDown()) {
2025 changed = TRUE;
2026 PRIVATE(this)->shiftDown = !PRIVATE(this)->shiftDown;
2027 }
2028
2029 SbString str;
2030
2031 if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
2032 int which = PRIVATE(this)->constraintState - CONSTRAINT_X;
2033 str.sprintf("%cAxisFeedbackSwitch", 'x' + which);
2034 this->setSwitchValue(str.getString(), 0);
2035 str.sprintf("%cAxisFeedbackSwitch", 'x' + (which+1)%3);
2036 this->setSwitchValue(str.getString(), SO_SWITCH_NONE);
2037 str.sprintf("%cAxisFeedbackSwitch", 'x' + (which+2)%3);
2038 this->setSwitchValue(str.getString(), SO_SWITCH_NONE);
2039 }
2040 else {
2041 str.sprintf("%cAxisFeedbackSwitch", 'x' + PRIVATE(this)->dimension);
2042 this->setSwitchValue(str.getString(), PRIVATE(this)->ctrlDown ? 0 : SO_SWITCH_NONE);
2043 int val = PRIVATE(this)->shiftDown ? 1 : 0;
2044 if (PRIVATE(this)->ctrlDown) val = SO_SWITCH_NONE;
2045 str.sprintf("%cAxisFeedbackSwitch", 'x' + (PRIVATE(this)->dimension+1)%3);
2046 this->setSwitchValue(str.getString(), val);
2047 str.sprintf("%cAxisFeedbackSwitch", 'x' + (PRIVATE(this)->dimension+2)%3);
2048 this->setSwitchValue(str.getString(), val);
2049 }
2050 return changed;
2051 }
2052
2053 SbBool
setDynamicScaleSwitches(const SoEvent * event)2054 SoTransformerDragger::setDynamicScaleSwitches(const SoEvent *event)
2055 {
2056 SbBool changed = FALSE;
2057 if (PRIVATE(this)->ctrlDown != event->wasCtrlDown()) {
2058 changed = TRUE;
2059 PRIVATE(this)->ctrlDown = !PRIVATE(this)->ctrlDown;
2060 }
2061 if (PRIVATE(this)->shiftDown != event->wasShiftDown()) {
2062 changed = TRUE;
2063 PRIVATE(this)->shiftDown = !PRIVATE(this)->shiftDown;
2064 }
2065 if (PRIVATE(this)->constraintState == CONSTRAINT_WAIT) {
2066 this->setSwitchValue("xAxisFeedbackSwitch", 1);
2067 this->setSwitchValue("yAxisFeedbackSwitch", 1);
2068 this->setSwitchValue("zAxisFeedbackSwitch", 1);
2069 this->setSwitchValue("radialFeedbackSwitch", SO_SWITCH_NONE);
2070 }
2071 else if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
2072 int which = PRIVATE(this)->constraintState - CONSTRAINT_X;
2073 SbString str;
2074 str.sprintf("%cAxisFeedbackSwitch", 'x' + which);
2075 this->setSwitchValue(str.getString(), 0);
2076 str.sprintf("%cAxisFeedbackSwitch", 'x' + (which+1)%3);
2077 this->setSwitchValue(str.getString(), SO_SWITCH_NONE);
2078 str.sprintf("%cAxisFeedbackSwitch", 'x' + (which+2)%3);
2079 this->setSwitchValue(str.getString(), SO_SWITCH_NONE);
2080 this->setSwitchValue("radialFeedbackSwitch", SO_SWITCH_NONE);
2081 }
2082 else {
2083 this->setSwitchValue("xAxisFeedbackSwitch", SO_SWITCH_NONE);
2084 this->setSwitchValue("yAxisFeedbackSwitch", SO_SWITCH_NONE);
2085 this->setSwitchValue("zAxisFeedbackSwitch", SO_SWITCH_NONE);
2086 this->setSwitchValue("radialFeedbackSwitch", 0);
2087 }
2088
2089 this->setSwitchValue("scaleBoxFeedbackSwitch", PRIVATE(this)->shiftDown ? 0 : SO_SWITCH_NONE);
2090
2091 if (PRIVATE(this)->ctrlDown) {
2092 SbVec3f pt = this->getLocalStartingPoint();
2093 if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
2094 int num = PRIVATE(this)->constraintState - CONSTRAINT_X;
2095 pt[(num+1)%3] = 0.0f;
2096 pt[(num+2)%3] = 0.0f;
2097 }
2098 SbString str;
2099 for (int i = 0; i < 3; i++) {
2100 str.sprintf("pos%cWallFeedbackSwitch", 'X' + i);
2101 this->setSwitchValue(str.getString(), pt[i] < 0.0f ? 0 : SO_SWITCH_NONE);
2102 str.sprintf("neg%cWallFeedbackSwitch", 'X' + i);
2103 this->setSwitchValue(str.getString(), pt[i] > 0.0f ? 0 : SO_SWITCH_NONE);
2104 }
2105 }
2106 else {
2107 this->setSwitchValue("posXWallFeedbackSwitch", SO_SWITCH_NONE);
2108 this->setSwitchValue("negXWallFeedbackSwitch", SO_SWITCH_NONE);
2109 this->setSwitchValue("posYWallFeedbackSwitch", SO_SWITCH_NONE);
2110 this->setSwitchValue("negYWallFeedbackSwitch", SO_SWITCH_NONE);
2111 this->setSwitchValue("posZWallFeedbackSwitch", SO_SWITCH_NONE);
2112 this->setSwitchValue("negZWallFeedbackSwitch", SO_SWITCH_NONE);
2113 }
2114 return changed;
2115 }
2116
2117
2118 SbBool
setDynamicRotatorSwitches(const SoEvent * event)2119 SoTransformerDragger::setDynamicRotatorSwitches(const SoEvent *event)
2120 {
2121 SbBool changed = FALSE;
2122 if (PRIVATE(this)->ctrlDown != event->wasCtrlDown()) {
2123 changed = TRUE;
2124 PRIVATE(this)->ctrlDown = !PRIVATE(this)->ctrlDown;
2125 }
2126 if (PRIVATE(this)->shiftDown != event->wasShiftDown()) {
2127 changed = TRUE;
2128 PRIVATE(this)->shiftDown = !PRIVATE(this)->shiftDown;
2129 }
2130
2131 SbString str;
2132 {
2133 int axis0 = PRIVATE(this)->whatnum-1;
2134 int axis1 = (axis0 & 1) ? axis0 - 1 : axis0 + 1;
2135
2136 str.sprintf("rotator%dSwitch", axis0 + 1);
2137 this->setSwitchValue(str.getString(), 1);
2138 str.sprintf("rotator%dSwitch", axis1 + 1);
2139 this->setSwitchValue(str.getString(), PRIVATE(this)->ctrlDown ? 0 : 1);
2140 }
2141
2142 int axisval[3];
2143 int circleval[3];
2144 int dim = PRIVATE(this)->dimension;
2145
2146 if (PRIVATE(this)->constraintState == CONSTRAINT_WAIT) {
2147 axisval[dim] = SO_SWITCH_NONE;
2148 axisval[(dim+1)%3] = 1;
2149 axisval[(dim+2)%3] = 1;
2150 circleval[dim] = SO_SWITCH_NONE;
2151 circleval[(dim+1)%3] = 0;
2152 circleval[(dim+2)%3] = 0;
2153 }
2154 else if (PRIVATE(this)->constraintState >= CONSTRAINT_X) {
2155 dim = PRIVATE(this)->constraintState - CONSTRAINT_X;
2156 axisval[dim] = 0;
2157 axisval[(dim+1)%3] = SO_SWITCH_NONE;
2158 axisval[(dim+2)%3] = SO_SWITCH_NONE;
2159
2160 const SbVec3f &n = this->planeProj->getPlane().getNormal();
2161 circleval[0] = n[0] != 0.0f ? 0 : SO_SWITCH_NONE;
2162 circleval[1] = n[1] != 0.0f ? 0 : SO_SWITCH_NONE;
2163 circleval[2] = n[2] != 0.0f ? 0 : SO_SWITCH_NONE;
2164 }
2165 else {
2166 circleval[0] = 0;
2167 circleval[1] = 0;
2168 circleval[2] = 0;
2169 axisval[0] = SO_SWITCH_NONE;
2170 axisval[1] = SO_SWITCH_NONE;
2171 axisval[2] = SO_SWITCH_NONE;
2172 }
2173 if (PRIVATE(this)->ctrlDown) {
2174 SoTransform *transform = SO_GET_ANY_PART(this, "circleFeedbackTransform", SoTransform);
2175 SbVec3f offset = -PRIVATE(this)->ctrlOffset * KNOB_DISTANCE;
2176 if (transform->translation.getValue() != offset)
2177 transform->translation = offset;
2178 if (transform->scaleFactor.getValue() != SbVec3f(2.0f, 2.0f, 2.0f))
2179 transform->scaleFactor = SbVec3f(2.0f, 2.0f, 2.0f);
2180 this->setSwitchValue("circleFeedbackTransformSwitch", SO_SWITCH_ALL);
2181 }
2182 else {
2183 this->setSwitchValue("circleFeedbackTransformSwitch", 0);
2184 }
2185
2186 this->setSwitchValue("xAxisFeedbackSwitch", axisval[0]);
2187 this->setSwitchValue("yAxisFeedbackSwitch", axisval[1]);
2188 this->setSwitchValue("zAxisFeedbackSwitch", axisval[2]);
2189 this->setSwitchValue("xCircleFeedbackSwitch", circleval[0]);
2190 this->setSwitchValue("yCircleFeedbackSwitch", circleval[1]);
2191 this->setSwitchValue("zCircleFeedbackSwitch", circleval[2]);
2192
2193 return changed;
2194 }
2195
2196
2197 // Undefine these again, as some of them are also used in other
2198 // dragger sourcecode files (which causes trouble when using the
2199 // compact build hack where all .cpp files are included into all.cpp).
2200
2201 #undef WHATKIND_NONE
2202 #undef WHATKIND_SCALE
2203 #undef WHATKIND_TRANSLATE
2204 #undef WHATKIND_ROTATE
2205
2206 #undef CONSTRAINT_OFF
2207 #undef CONSTRAINT_WAIT
2208 #undef CONSTRAINT_X
2209 #undef CONSTRAINT_Y
2210 #undef CONSTRAINT_Z
2211
2212 #undef KNOB_DISTANCE
2213
2214 #undef PRIVATE
2215 #undef THISP
2216
2217 #ifdef COIN_TEST_SUITE
2218
2219 #include <Inventor/SbDict.h>
2220 #include <Inventor/actions/SoCallbackAction.h>
2221 #include <Inventor/nodes/SoSeparator.h>
2222
2223 static
2224 SoCallbackAction::Response
register_cb(void * data,SoCallbackAction * action,const SoNode * node)2225 register_cb(void * data, SoCallbackAction * action, const SoNode * node)
2226 {
2227 assert(data);
2228 SbDict * dict = static_cast<SbDict *>(data);
2229 dict->enter(reinterpret_cast<uintptr_t>(node), NULL);
2230 return SoCallbackAction::CONTINUE;
2231 }
2232
2233 static
2234 void
ensure_unique_cb(uintptr_t entry,void * value,void * data)2235 ensure_unique_cb(uintptr_t entry, void * value, void * data)
2236 {
2237 SbDict * copydict = static_cast<SbDict *>(data);
2238 void * val = NULL;
2239 BOOST_ASSERT(!copydict->find(entry, val));
2240 }
2241
BOOST_AUTO_TEST_CASE(dragger_deep_copy)2242 BOOST_AUTO_TEST_CASE(dragger_deep_copy)
2243 {
2244 SbDict origdict, copydict;
2245
2246 SoSeparator * root = new SoSeparator;
2247 root->setName("dragger_deep_copy_root");
2248 root->ref();
2249 root->addChild(new SoTransformerDragger);
2250
2251 SoSeparator * copy = static_cast<SoSeparator *>(root->copy());
2252 assert(copy);
2253 copy->setName("dragger_deep_copy_copy");
2254 copy->ref();
2255
2256 {
2257 SoCallbackAction cba;
2258 cba.setCallbackAll(TRUE);
2259
2260 cba.addPreCallback(SoNode::getClassTypeId(), register_cb, &origdict);
2261 cba.apply(root);
2262 }
2263
2264 {
2265 SoCallbackAction cba;
2266 cba.setCallbackAll(TRUE);
2267
2268 cba.addPreCallback(SoNode::getClassTypeId(), register_cb, ©dict);
2269 cba.apply(copy);
2270 }
2271
2272 SbPList keys, values;
2273
2274 origdict.makePList(keys, values);
2275 const int origdictsize = keys.getLength();
2276
2277 keys.truncate(0);
2278 values.truncate(0);
2279 copydict.makePList(keys, values);
2280 const int copydictsize = keys.getLength();
2281
2282 BOOST_ASSERT(origdictsize == copydictsize);
2283
2284 // make sure pointer sets have an empty union
2285 origdict.applyToAll(ensure_unique_cb, ©dict);
2286
2287 root->unref();
2288 copy->unref();
2289 }
2290
2291 #endif // COIN_TEST_SUITE
2292
2293 #endif // HAVE_DRAGGERS
2294