sunrize 1.5.13 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/package.json +5 -5
  2. package/src/Application/Application.js +2 -7
  3. package/src/Application/Dashboard.js +10 -10
  4. package/src/Application/DataStorage.js +177 -177
  5. package/src/Application/Document.js +72 -127
  6. package/src/Application/Interface.js +4 -0
  7. package/src/Application/Tabs.js +3 -3
  8. package/src/Controls/Dialog.js +3 -1
  9. package/src/Editors/BrowserFrame.js +171 -0
  10. package/src/Editors/OutlineEditor.js +149 -123
  11. package/src/Editors/OutlineRouteGraph.js +493 -493
  12. package/src/Editors/OutlineView.js +102 -64
  13. package/src/Editors/SceneProperties.js +137 -136
  14. package/src/Editors/ScriptEditor.js +1 -1
  15. package/src/Tools/Core/X3DNodeTool.js +66 -12
  16. package/src/Tools/Grids/AngleGridTool.js +0 -5
  17. package/src/Tools/Grids/AngleGridTool.x3d +1 -0
  18. package/src/Tools/Grids/AxonometricGrid.x3d +5 -5
  19. package/src/Tools/Grids/AxonometricGridTool.js +0 -5
  20. package/src/Tools/Grids/AxonometricGridTool.x3d +1 -0
  21. package/src/Tools/Grids/GridTool.js +0 -5
  22. package/src/Tools/Grids/GridTool.x3d +1 -0
  23. package/src/Tools/Grids/X3DGridNodeTool.js +131 -84
  24. package/src/Tools/Grouping/X3DTransformNodeTool.js +19 -21
  25. package/src/Tools/Grouping/X3DTransformNodeTool.x3d +20 -15
  26. package/src/Tools/Layering/X3DActiveLayerNodeTool.js +16 -21
  27. package/src/Tools/Lighting/DirectionalLightTool.js +32 -1
  28. package/src/Tools/Lighting/X3DLightNodeTool.x3d +4 -21
  29. package/src/Tools/Shaders/TextureShader.x3d +16 -3
  30. package/src/Tools/SnapTool/{SnapSourceTool.js → SnapSource.js} +2 -7
  31. package/src/Tools/SnapTool/SnapTarget.js +650 -0
  32. package/src/Tools/SnapTool/SnapTool.x3d +28 -27
  33. package/src/Tools/SnapTool/X3DSnapNodeTool.js +16 -15
  34. package/src/Tools/Sound/SoundTool.x3d +4 -21
  35. package/src/Tools/TextureProjection/X3DTextureProjectorNodeTool.x3d +19 -26
  36. package/src/Undo/Editor.js +185 -46
  37. package/src/assets/Info.plist +56 -56
  38. package/src/assets/themes/default-template.css +1 -0
  39. package/src/assets/themes/default.css +1 -0
  40. package/src/Editors/BrowserSize.js +0 -101
  41. package/src/Tools/SnapTool/SnapTargetTool.js +0 -20
@@ -17,9 +17,17 @@ class X3DNodeTool extends X3DBaseTool
17
17
  {
18
18
  static createOnSelection = true;
19
19
  static createOnDemand = true;
20
+ static tools = new Set (); // Set of all X3DNodeTool tools.
21
+
22
+ static #gridNode = null;
23
+ static get gridNode () { return X3DNodeTool .#gridNode; }
24
+ static set gridNode (value) { X3DNodeTool .#gridNode = value; }
25
+
26
+ static #snapTarget = false;
27
+ static get snapTarget () { return X3DNodeTool .#snapTarget; }
28
+ static set snapTarget (value) { X3DNodeTool .#snapTarget = value; }
20
29
 
21
30
  static #scenes = new Map (); // Loaded tool proto scenes.
22
- static tools = new Set (); // Set of all this tools.
23
31
  static #sensors = [ ]; // Always empty
24
32
 
25
33
  tool = null;
@@ -140,6 +148,7 @@ class X3DNodeTool extends X3DBaseTool
140
148
  {
141
149
  const scene = await this .getBrowser () .createX3DFromURL (new X3D .MFString (protoURL));
142
150
 
151
+ scene .setExecutionContext (scene);
143
152
  scene .setLive (true);
144
153
 
145
154
  for (const externproto of scene .externprotos)
@@ -239,13 +248,15 @@ class X3DNodeTool extends X3DBaseTool
239
248
 
240
249
  handleUndo (active)
241
250
  {
251
+ // This function is also called in OutlineEditor beginUndoSetFieldValue and endUndoSetFieldValue.
252
+
242
253
  if (!this .tool .undo)
243
254
  return;
244
255
 
245
256
  if (active .getValue ())
246
257
  this .prepareUndo ();
247
258
  else
248
- requestAnimationFrame (() => this .finishUndo ());
259
+ this .finishUndo ();
249
260
  }
250
261
 
251
262
  prepareUndo ()
@@ -360,18 +371,64 @@ class X3DNodeTool extends X3DBaseTool
360
371
  undoSaveInitialValues (fields)
361
372
  {
362
373
  for (const name of fields)
363
- this .#initialValues .set (name, this .getField (name) .copy ());
374
+ {
375
+ try
376
+ {
377
+ this .#initialValues .set (name, this .getField (name) .copy ());
378
+ }
379
+ catch
380
+ {
381
+ this .#initialValues .set (name, this .tool .getField (name) .copy ());
382
+ }
383
+ }
364
384
  }
365
385
 
366
386
  undoSetValues ()
367
387
  {
368
388
  for (const [name, initialValue] of this .#initialValues)
369
389
  {
370
- const value = this .getField (name) .copy ();
390
+ try
391
+ {
392
+ const value = this .getField (name) .copy ();
371
393
 
372
- this .getField (name) .assign (initialValue);
394
+ switch (value .getType ())
395
+ {
396
+ case X3D .X3DConstants .SFRotation:
397
+ case X3D .X3DConstants .SFVec2d:
398
+ case X3D .X3DConstants .SFVec2f:
399
+ case X3D .X3DConstants .SFVec3d:
400
+ case X3D .X3DConstants .SFVec3f:
401
+ case X3D .X3DConstants .SFVec4d:
402
+ case X3D .X3DConstants .SFVec4f:
403
+ Editor .roundToIntegerIfAlmostEqual (value);
404
+ break;
405
+ }
373
406
 
374
- Editor .setFieldValue (this .getExecutionContext (), this .node, this .getField (name), value);
407
+ this .getField (name) .assign (initialValue);
408
+
409
+ Editor .setFieldValue (this .getExecutionContext (), this .node, this .getField (name), value);
410
+ }
411
+ catch
412
+ {
413
+ const value = this .tool .getField (name) .copy ();
414
+
415
+ switch (value .getType ())
416
+ {
417
+ case X3D .X3DConstants .SFRotation:
418
+ case X3D .X3DConstants .SFVec2d:
419
+ case X3D .X3DConstants .SFVec2f:
420
+ case X3D .X3DConstants .SFVec3d:
421
+ case X3D .X3DConstants .SFVec3f:
422
+ case X3D .X3DConstants .SFVec4d:
423
+ case X3D .X3DConstants .SFVec4f:
424
+ Editor .roundToIntegerIfAlmostEqual (value);
425
+ break;
426
+ }
427
+
428
+ this .setMetaData (`${this .getTypeName ()}/${name}`, initialValue);
429
+
430
+ Editor .setNodeMetaData (this .node, `${this .getTypeName ()}/${name}`, value);
431
+ }
375
432
  }
376
433
 
377
434
  this .#initialValues .clear ();
@@ -389,13 +446,10 @@ class X3DNodeTool extends X3DBaseTool
389
446
  {
390
447
  case X3D .TraverseType .POINTER:
391
448
  {
392
- if ($("#secondary-toolbar .hand") .hasClass ("active"))
393
- return;
449
+ if (this .toolPointingEnabled)
450
+ break;
394
451
 
395
- if (!this .toolPointingEnabled)
396
- return;
397
-
398
- break;
452
+ return;
399
453
  }
400
454
  }
401
455
 
@@ -6,11 +6,6 @@ const
6
6
 
7
7
  class AngleGridTool extends X3DGridNodeTool
8
8
  {
9
- constructor (executionContext)
10
- {
11
- super (executionContext);
12
- }
13
-
14
9
  async initializeTool ()
15
10
  {
16
11
  await super .initializeTool (__dirname, "AngleGridTool.x3d");
@@ -63,6 +63,7 @@
63
63
  </ProtoDeclare>
64
64
  <ProtoDeclare name='AngleGridTool'>
65
65
  <ProtoInterface>
66
+ <field accessType='inputOutput' type='SFBool' name='visible'/>
66
67
  <field accessType='inputOutput' type='SFVec3f' name='translation'/>
67
68
  <field accessType='inputOutput' type='SFRotation' name='rotation'/>
68
69
  <field accessType='inputOutput' type='SFVec3f' name='scale' value='1 1 1'/>
@@ -222,14 +222,14 @@ function generateGridAxis (axis, hexagon, major, grid, coordIndex, p)
222
222
  p2 = c .lerp (d, t)
223
223
  add = major / (4 * p1 .distance (p2));
224
224
 
225
- point [p] = p1 .lerp (p2, 0 - add);
226
- point [p + 1] = p1 .lerp (p2, 1 + add);
225
+ point [p] = p1 .lerp (p2, 0 - add);
226
+ point [p + 1] = p1 .lerp (p2, 1 + add);
227
227
 
228
228
  coordIndex [coordIndex .length] = p;
229
- coordIndex [coordIndex .length] = p + 1;
230
- coordIndex [coordIndex .length] = -1;
229
+ coordIndex [coordIndex .length] = p + 1;
230
+ coordIndex [coordIndex .length] = -1;
231
231
 
232
- p += 2;
232
+ p += 2;
233
233
  }
234
234
 
235
235
  return p;
@@ -7,11 +7,6 @@ const
7
7
 
8
8
  class AxonometricGridTool extends X3DGridNodeTool
9
9
  {
10
- constructor (executionContext)
11
- {
12
- super (executionContext);
13
- }
14
-
15
10
  async initializeTool ()
16
11
  {
17
12
  await super .initializeTool (__dirname, "AxonometricGridTool.x3d");
@@ -65,6 +65,7 @@
65
65
  </ProtoDeclare>
66
66
  <ProtoDeclare name='AxonometricGridTool'>
67
67
  <ProtoInterface>
68
+ <field accessType='inputOutput' type='SFBool' name='visible'/>
68
69
  <field accessType='inputOutput' type='SFVec3f' name='translation'/>
69
70
  <field accessType='inputOutput' type='SFRotation' name='rotation'/>
70
71
  <field accessType='inputOutput' type='SFVec3f' name='scale' value='1 1 1'/>
@@ -6,11 +6,6 @@ const
6
6
 
7
7
  class GridTool extends X3DGridNodeTool
8
8
  {
9
- constructor (executionContext)
10
- {
11
- super (executionContext);
12
- }
13
-
14
9
  async initializeTool ()
15
10
  {
16
11
  await super .initializeTool (__dirname, "GridTool.x3d");
@@ -53,6 +53,7 @@
53
53
  </ProtoDeclare>
54
54
  <ProtoDeclare name='GridTool'>
55
55
  <ProtoInterface>
56
+ <field accessType='inputOutput' type='SFBool' name='visible'/>
56
57
  <field accessType='inputOutput' type='SFVec3f' name='translation'/>
57
58
  <field accessType='inputOutput' type='SFRotation' name='rotation'/>
58
59
  <field accessType='inputOutput' type='SFVec3f' name='scale' value='1 1 1'/>
@@ -3,30 +3,44 @@
3
3
  const
4
4
  X3DActiveLayerNodeTool = require ("../Layering/X3DActiveLayerNodeTool"),
5
5
  X3D = require ("../../X3D"),
6
- ActionKeys = require ("../../Application/ActionKeys");
6
+ ActionKeys = require ("../../Application/ActionKeys"),
7
+ Editor = require ("../../Undo/Editor.js"),
8
+ $ = require ("jquery");
7
9
 
8
10
  class X3DGridNodeTool extends X3DActiveLayerNodeTool
9
11
  {
10
12
  #transformTools = [ ];
11
- #events = Symbol ();
12
13
  #changing = Symbol ();
13
14
 
14
- constructor (executionContext)
15
- {
16
- super (executionContext);
17
- }
18
-
19
15
  async initializeTool (... args)
20
16
  {
21
17
  await super .initializeTool (... args);
22
18
 
19
+ this .tool .getField ("visible") .addReference (this ._visible);
23
20
  this .tool .getField ("translation") .setUnit ("length");
21
+
22
+ for (const field of this .tool .getValue () .getFields ())
23
+ {
24
+ if (!field .isInitializable ())
25
+ continue;
26
+
27
+ switch (field .getType ())
28
+ {
29
+ case X3D .X3DConstants .SFNode:
30
+ case X3D .X3DConstants .MFNode:
31
+ continue;
32
+ }
33
+
34
+ field .addInterest ("saveGrid", this);
35
+ }
24
36
  }
25
37
 
26
38
  connectTool ()
27
39
  {
28
40
  super .connectTool ();
29
41
 
42
+ X3DGridNodeTool .gridNode = this;
43
+
30
44
  X3DGridNodeTool .addToolInterest (this, () => this .set_transform_tools ());
31
45
 
32
46
  this .set_transform_tools ();
@@ -39,13 +53,61 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
39
53
  super .disconnectTool ();
40
54
  }
41
55
 
42
- set_transform_tools ()
56
+ configureTool ()
43
57
  {
44
- for (const transformTool of this .#transformTools)
58
+ this .restoreGrid ();
59
+ }
60
+
61
+ restoreGrid ()
62
+ {
63
+ if (!this .toolLayerNode)
64
+ return;
65
+
66
+ const configNode = Editor .getConfigNode (this .getBrowser ());
67
+
68
+ for (const field of this .tool .getValue () .getFields ())
69
+ {
70
+ if (!field .isInitializable ())
71
+ continue;
72
+
73
+ switch (field .getType ())
74
+ {
75
+ case X3D .X3DConstants .SFNode:
76
+ case X3D .X3DConstants .MFNode:
77
+ continue;
78
+ }
79
+
80
+ field .assign (this .tool .getFieldDefinition (field .getName ()) .value);
81
+
82
+ configNode ?.getMetaData (`Sunrize/${this .tool .getNodeTypeName ()}/${field .getName ()}`, field);
83
+ }
84
+ }
85
+
86
+ saveGrid (field)
87
+ {
88
+ if (!this .toolLayerNode)
89
+ return;
90
+
91
+ const path = `Sunrize/${this .tool .getNodeTypeName ()}/${field .getName ()}`;
92
+
93
+ if (field .equals (this .tool .getFieldDefinition (field .getName ()) .value))
94
+ {
95
+ const configNode = Editor .getConfigNode (this .getBrowser ());
96
+
97
+ configNode ?.removeMetaData (path);
98
+ }
99
+ else
45
100
  {
46
- transformTool .tool .getField ("isActive") .removeInterest ("set_active", this);
47
- transformTool .removeInterest ("set_transform", this);
101
+ const configNode = Editor .getConfigNode (this .getBrowser (), true);
102
+
103
+ configNode .setMetaData (path, field);
48
104
  }
105
+ }
106
+
107
+ set_transform_tools ()
108
+ {
109
+ for (const transformTool of this .#transformTools)
110
+ transformTool .removeInterest ("set_transform", this);
49
111
 
50
112
  this .#transformTools .length = 0;
51
113
 
@@ -58,21 +120,10 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
58
120
  }
59
121
 
60
122
  for (const transformTool of this .#transformTools)
61
- {
62
- transformTool .tool .getField ("isActive") .addInterest ("set_active", this, transformTool);
63
- transformTool .addInterest ("set_transform", this, transformTool, false);
64
- }
123
+ transformTool .addInterest ("set_transform", this, transformTool);
65
124
  }
66
125
 
67
- set_active (transformTool, active)
68
- {
69
- if (active .getValue ())
70
- transformTool .setUserData (this .#events, false);
71
- else
72
- this .set_transform (transformTool, transformTool .getUserData (this .#events));
73
- }
74
-
75
- set_transform (transformTool, active)
126
+ set_transform (transformTool)
76
127
  {
77
128
  if (!this ._visible .getValue ())
78
129
  return;
@@ -80,10 +131,13 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
80
131
  if (ActionKeys .value === (ActionKeys .Shift | ActionKeys .Control))
81
132
  return;
82
133
 
134
+ if (X3DGridNodeTool .snapTarget)
135
+ return;
136
+
83
137
  if (!this .tool .snapping)
84
138
  return;
85
139
 
86
- if (!(active || transformTool .tool .isActive))
140
+ if (!transformTool .tool .isActive)
87
141
  return;
88
142
 
89
143
  switch (transformTool .tool .activeTool)
@@ -102,46 +156,44 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
102
156
 
103
157
  set_translation (transformTool)
104
158
  {
105
- transformTool .setUserData (this .#events, true);
106
-
107
159
  if (transformTool .getUserData (this .#changing))
108
160
  {
109
161
  transformTool .setUserData (this .#changing, false);
110
162
  return;
111
163
  }
112
164
 
113
- // The position is transformed to an absolute position and then transformed into the coordinate system of the grid
114
- // for easier snapping position calculation.
165
+ // The position is transformed to an absolute position and then transformed into the coordinate system of the grid
166
+ // for easier snapping position calculation.
115
167
 
116
- // Get absolute position.
168
+ // Get absolute position.
117
169
 
118
- const absoluteMatrix = transformTool .getCurrentMatrix () .multRight (transformTool .getModelMatrix ());
170
+ const absoluteMatrix = transformTool .getCurrentMatrix () .multRight (transformTool .getModelMatrix ());
119
171
 
120
- if (transformTool .tool .keepCenter || !this .tool .snapToCenter)
121
- {
122
- // snapping to bbox center.
123
- var position = transformTool .getSubBBox (new X3D .Box3 ()) .multRight (absoluteMatrix) .center;
124
- }
125
- else
126
- {
127
- var position = absoluteMatrix .multVecMatrix (transformTool ._center .getValue () .copy ());
128
- }
172
+ if (transformTool .tool .keepCenter || !this .tool .snapToCenter)
173
+ {
174
+ // snapping to bbox center.
175
+ var position = transformTool .getSubBBox (new X3D .Box3 ()) .multRight (absoluteMatrix) .center;
176
+ }
177
+ else
178
+ {
179
+ var position = absoluteMatrix .multVecMatrix (transformTool ._center .getValue () .copy ());
180
+ }
129
181
 
130
- // Calculate snapping position and apply absolute translation.
182
+ // Calculate snapping position and apply absolute translation.
131
183
 
132
184
  const
133
185
  gridMatrix = this .getGridMatrix (),
134
186
  invGridMatrix = gridMatrix .copy () .inverse ();
135
187
 
136
- const
188
+ const
137
189
  snapMatrix = new X3D .Matrix4 () .set (gridMatrix .multVecMatrix (this .getSnapPosition (invGridMatrix .multVecMatrix (position .copy ()), true)) .subtract (position)),
138
- currentMatrix = absoluteMatrix .multRight (snapMatrix) .multRight (transformTool .getModelMatrix () .copy () .inverse ());
190
+ currentMatrix = absoluteMatrix .multRight (snapMatrix) .multRight (transformTool .getModelMatrix () .copy () .inverse ());
139
191
 
140
192
  transformTool .setUserData (this .#changing, true);
141
193
 
142
- if (transformTool .tool .keepCenter)
194
+ if (transformTool .tool .keepCenter)
143
195
  transformTool .setMatrixKeepCenter (currentMatrix);
144
- else
196
+ else
145
197
  transformTool .setMatrixWithCenter (currentMatrix);
146
198
  }
147
199
 
@@ -153,8 +205,6 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
153
205
 
154
206
  set_rotation (transformTool)
155
207
  {
156
- transformTool .setUserData (this .#events, true);
157
-
158
208
  if (transformTool .getUserData (this .#changing))
159
209
  {
160
210
  transformTool .setUserData (this .#changing, false);
@@ -163,17 +213,17 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
163
213
 
164
214
  // Snap rotation to axes.
165
215
 
166
- const absoluteMatrix = transformTool .getCurrentMatrix () .copy () .multRight (transformTool .getModelMatrix ()); // Matrix after transformation
216
+ const absoluteMatrix = transformTool .getCurrentMatrix () .copy () .multRight (transformTool .getModelMatrix ()); // Matrix after transformation
167
217
 
168
218
  const
169
219
  index0 = X3DGridNodeTool .#rotationAxes [transformTool .tool .activeHandle], // Index of rotation axis
170
220
  index1 = (index0 + 1) % 3,
171
221
  index2 = (index0 + 2) % 3;
172
222
 
173
- const y = [
223
+ const y = [
174
224
  absoluteMatrix .xAxis .copy (),
175
225
  absoluteMatrix .yAxis .copy (),
176
- absoluteMatrix .zAxis .copy ()
226
+ absoluteMatrix .zAxis .copy (),
177
227
  ]; // Rotation axis, equates to grid normal
178
228
 
179
229
  const z = [
@@ -182,27 +232,27 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
182
232
  absoluteMatrix .yAxis .copy (),
183
233
  ]; // Axis which snaps, later transformed to grid space
184
234
 
185
- const gridMatrix = this .getGridMatrix ();
235
+ const gridMatrix = this .getGridMatrix ();
186
236
 
187
237
  const
188
- Y = y [index1] .copy () .cross (y [index2]) .normalize (), // Normal of rotation plane
189
- X = gridMatrix .yAxis .copy () .cross (Y), // Intersection between both planes
190
- Z = X .copy () .cross (Y), // Front vector
191
- gridPlane = gridMatrix .submatrix .copy ();
238
+ Y = y [index1] .copy () .cross (y [index2]) .normalize (), // Normal of rotation plane
239
+ X = gridMatrix .yAxis .copy () .cross (Y), // Intersection between both planes
240
+ Z = X .copy () .cross (Y), // Front vector
241
+ gridPlane = gridMatrix .submatrix .copy ();
192
242
 
193
243
  let
194
- rotationPlane = new X3D .Matrix3 (X [0], X [1], X [2], Y [0], Y [1], Y [2], Z [0], Z [1], Z [2]),
195
- gridRotation = this .tool .rotation .getValue () .getMatrix ();
244
+ rotationPlane = new X3D .Matrix3 (X [0], X [1], X [2], Y [0], Y [1], Y [2], Z [0], Z [1], Z [2]),
245
+ gridRotation = this .tool .rotation .getValue () .getMatrix ();
196
246
 
197
- // If X or Z are near 0 then Y is collinear to the y-axis.
247
+ // If X or Z are near 0 then Y is collinear to the y-axis.
198
248
 
199
- if (1 - Math .abs (gridMatrix .yAxis .normalize () .dot (Y)) < 1e-6)
200
- {
201
- rotationPlane = new X3D .Matrix3 ();
202
- gridRotation = new X3D .Matrix3 ();
203
- }
249
+ if (1 - Math .abs (gridMatrix .yAxis .normalize () .dot (Y)) < 1e-6)
250
+ {
251
+ rotationPlane = new X3D .Matrix3 ();
252
+ gridRotation = new X3D .Matrix3 ();
253
+ }
204
254
 
205
- const
255
+ const
206
256
  vectorToSnap = z [index0],
207
257
  vectorOnGrid = rotationPlane .copy () .inverse () .multRight (gridRotation) .multRight (gridPlane .copy () .inverse ()) .multVecMatrix (vectorToSnap .copy ()) .normalize (), // Vector inside grid space.
208
258
  snapVector = rotationPlane .multVecMatrix (gridRotation .copy () .inverse () .multVecMatrix (gridPlane .multVecMatrix (this .getSnapPosition (vectorOnGrid .copy (), false)))),
@@ -212,19 +262,19 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
212
262
  invModelMatrix .multDirMatrix (snapVector .copy ())
213
263
  );
214
264
 
215
- const currentMatrix = new X3D .Matrix4 ()
265
+ const currentMatrix = new X3D .Matrix4 ()
216
266
  .set (transformTool ._translation .getValue (),
217
- transformTool ._rotation .getValue () .copy () .multRight (snapRotation),
218
- transformTool ._scale .getValue (),
219
- transformTool ._scaleOrientation .getValue (),
220
- transformTool ._center .getValue ());
267
+ transformTool ._rotation .getValue () .copy () .multRight (snapRotation),
268
+ transformTool ._scale .getValue (),
269
+ transformTool ._scaleOrientation .getValue (),
270
+ transformTool ._center .getValue ());
221
271
 
222
272
  transformTool .setUserData (this .#changing, true);
223
273
 
224
- if (transformTool .tool .keepCenter)
225
- transformTool .setMatrixKeepCenter (currentMatrix);
226
- else
227
- transformTool .setMatrixWithCenter (currentMatrix);
274
+ if (transformTool .tool .keepCenter)
275
+ transformTool .setMatrixKeepCenter (currentMatrix);
276
+ else
277
+ transformTool .setMatrixWithCenter (currentMatrix);
228
278
  }
229
279
 
230
280
  static #scaleHandles = {
@@ -246,28 +296,26 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
246
296
 
247
297
  set_scale (transformTool)
248
298
  {
249
- transformTool .setUserData (this .#events, true);
250
-
251
299
  if (transformTool .getUserData (this .#changing))
252
300
  {
253
301
  transformTool .setUserData (this .#changing, false);
254
302
  return;
255
303
  }
256
304
 
257
- const handle = X3DGridNodeTool .#scaleHandles [transformTool .tool .activeHandle];
305
+ const handle = X3DGridNodeTool .#scaleHandles [transformTool .tool .activeHandle];
258
306
 
259
- // All points are first transformed to grid space, then a snapping position is calculated, and then transformed back to absolute space.
307
+ // All points are first transformed to grid space, then a snapping position is calculated, and then transformed back to absolute space.
260
308
 
261
- const currentMatrix = handle < 6
309
+ const currentMatrix = handle < 6
262
310
  ? this .getScaleMatrix (transformTool, handle)
263
311
  : this .getUniformScaleMatrix (transformTool, handle - 6);
264
312
 
265
313
  transformTool .setUserData (this .#changing, true);
266
314
 
267
- if (transformTool .tool .keepCenter)
268
- transformTool .setMatrixKeepCenter (currentMatrix);
269
- else
270
- transformTool .setMatrixWithCenter (currentMatrix);
315
+ if (transformTool .tool .keepCenter)
316
+ transformTool .setMatrixKeepCenter (currentMatrix);
317
+ else
318
+ transformTool .setMatrixWithCenter (currentMatrix);
271
319
  }
272
320
 
273
321
  static #axes = [
@@ -482,8 +530,7 @@ class X3DGridNodeTool extends X3DActiveLayerNodeTool
482
530
  const tool = this .tool;
483
531
 
484
532
  return new X3D .Matrix4 ()
485
- .set (tool .translation .getValue (), tool .rotation .getValue (), tool .scale .getValue ())
486
- .multRight (this .getModelMatrix ());
533
+ .set (tool .translation .getValue (), tool .rotation .getValue (), tool .scale .getValue ());
487
534
  }
488
535
  }
489
536
 
@@ -79,11 +79,6 @@ class X3DTransformNodeTool extends X3DChildNodeTool
79
79
  #initialScaleOrientation;
80
80
  #initialCenter;
81
81
 
82
- prepareUndo ()
83
- {
84
- super .prepareUndo ();
85
- }
86
-
87
82
  beginUndo ()
88
83
  {
89
84
  if (this .isHidden ())
@@ -92,6 +87,9 @@ class X3DTransformNodeTool extends X3DChildNodeTool
92
87
  if (!this ._visible .getValue ())
93
88
  return false;
94
89
 
90
+ if (!this .tool .undo)
91
+ return false;
92
+
95
93
  this .#initialMatrix .assign (this .getCurrentMatrix ());
96
94
 
97
95
  this .#initialTranslation = this ._translation .copy ();
@@ -137,19 +135,19 @@ class X3DTransformNodeTool extends X3DChildNodeTool
137
135
 
138
136
  transformGroups ()
139
137
  {
140
- if (!this .tool .isActive)
138
+ if (this .isHidden ())
141
139
  return;
142
140
 
143
- if (!this .tool .activeTool .match (/^(?:TRANSLATE|ROTATE|SCALE)$/))
141
+ if (!this ._visible .getValue ())
144
142
  return;
145
143
 
146
- if (this .isHidden ())
144
+ if (this .tool .group === "NONE")
147
145
  return;
148
146
 
149
- if (!this ._visible .getValue ())
147
+ if (!this .tool .activeTool .match (/^(?:TRANSLATE|ROTATE|SCALE)$/))
150
148
  return;
151
149
 
152
- if (this .tool .group === "NONE")
150
+ if (!(this .tool .isActive || this .tool .active))
153
151
  return;
154
152
 
155
153
  const differenceMatrix = this .#initialMatrix .copy ()
@@ -191,21 +189,21 @@ class X3DTransformNodeTool extends X3DChildNodeTool
191
189
  scale = new X3D .Vector3 (1, 1, 1),
192
190
  scaleOrientation = new X3D .Rotation4 ();
193
191
 
194
- matrix .get (translation, rotation, scale, scaleOrientation);
192
+ matrix .get (translation, rotation, scale, scaleOrientation);
195
193
 
196
- if (!this .tool .tools .includes ("TRANSLATE"))
197
- translation .set (0, 0, 0);
194
+ if (!this .tool .tools .includes ("TRANSLATE"))
195
+ translation .set (0, 0, 0);
198
196
 
199
- if (!this .tool .tools .includes ("ROTATE"))
200
- rotation .set (0, 0, 1, 0);
197
+ if (!this .tool .tools .includes ("ROTATE"))
198
+ rotation .set (0, 0, 1, 0);
201
199
 
202
- if (!this .tool .tools .includes ("SCALE"))
200
+ if (!this .tool .tools .includes ("SCALE"))
203
201
  {
204
- scale .set (1, 1, 1);
205
- scaleOrientation .set (0, 0, 1, 0);
202
+ scale .set (1, 1, 1);
203
+ scaleOrientation .set (0, 0, 1, 0);
206
204
  }
207
205
 
208
- matrix .set (translation, rotation, scale, scaleOrientation);
206
+ matrix .set (translation, rotation, scale, scaleOrientation);
209
207
 
210
208
  if (keepCenter)
211
209
  this .setMatrixKeepCenter (matrix);
@@ -219,9 +217,9 @@ class X3DTransformNodeTool extends X3DChildNodeTool
219
217
  .add (this ._translation .getValue ())
220
218
  .subtract (matrix .origin);
221
219
 
222
- matrix .copy () .inverse () .multDirMatrix (center);
220
+ matrix .copy () .inverse () .multDirMatrix (center);
223
221
 
224
- this .setMatrixWithCenter (matrix, center);
222
+ this .setMatrixWithCenter (matrix, center);
225
223
  }
226
224
 
227
225
  setMatrixWithCenter (matrix, center = this ._center .getValue ())