@shopware-ag/dive 1.5.0 → 1.6.1

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 (43) hide show
  1. package/README.md +38 -25
  2. package/build/dive.cjs +717 -500
  3. package/build/dive.cjs.map +1 -1
  4. package/build/dive.d.cts +174 -113
  5. package/build/dive.d.ts +174 -113
  6. package/build/dive.js +716 -486
  7. package/build/dive.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/__test__/DIVE.test.ts +66 -22
  10. package/src/animation/AnimationSystem.ts +16 -0
  11. package/src/animation/__test__/AnimationSystem.test.ts +23 -2
  12. package/src/axiscamera/AxisCamera.ts +40 -2
  13. package/src/axiscamera/__test__/AxisCamera.test.ts +178 -5
  14. package/src/com/Communication.ts +50 -16
  15. package/src/com/__test__/Communication.test.ts +73 -24
  16. package/src/com/actions/camera/computeencompassingview.ts +9 -0
  17. package/src/com/actions/index.ts +2 -0
  18. package/src/com/actions/scene/updatescene.ts +1 -0
  19. package/src/controls/OrbitControls.ts +14 -2
  20. package/src/controls/__test__/OrbitControls.test.ts +31 -4
  21. package/src/dive.ts +93 -33
  22. package/src/grid/Grid.ts +4 -0
  23. package/src/grid/__test__/Grid.test.ts +7 -0
  24. package/src/interface/Selectable.ts +17 -0
  25. package/src/interface/__test__/Interfaces.test.ts +18 -0
  26. package/src/mediacreator/MediaCreator.ts +2 -2
  27. package/src/mediacreator/__test__/MediaCreator.test.ts +12 -10
  28. package/src/model/Model.ts +1 -1
  29. package/src/model/__test__/Model.test.ts +8 -1
  30. package/src/renderer/Renderer.ts +7 -1
  31. package/src/renderer/__test__/Renderer.test.ts +14 -5
  32. package/src/scene/Scene.ts +8 -2
  33. package/src/scene/__test__/Scene.test.ts +6 -0
  34. package/src/scene/root/Root.ts +11 -1
  35. package/src/scene/root/__test__/Root.test.ts +68 -2
  36. package/src/toolbox/BaseTool.ts +1 -1
  37. package/src/toolbox/Toolbox.ts +53 -37
  38. package/src/toolbox/__test__/BaseTool.test.ts +43 -7
  39. package/src/toolbox/__test__/Toolbox.test.ts +39 -44
  40. package/src/toolbox/select/SelectTool.ts +17 -28
  41. package/src/toolbox/select/__test__/SelectTool.test.ts +21 -12
  42. package/src/toolbox/transform/TransformTool.ts +7 -1
  43. package/src/toolbox/transform/__test__/TransformTool.test.ts +22 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "./build/dive.cjs",
@@ -30,34 +30,58 @@ jest.mock('three', () => {
30
30
  }
31
31
  });
32
32
 
33
- jest.mock('../renderer/Renderer.ts', () => {
33
+ jest.mock('three/src/math/MathUtils', () => {
34
+ return {
35
+ generateUUID: () => { return 'test_uuid'; },
36
+ }
37
+ });
38
+
39
+ jest.mock('../com/Communication.ts', () => {
34
40
  return jest.fn(function () {
35
- this.domElement = {
36
- clientWidth: 800,
37
- clientHeight: 600,
38
- style: {
39
- position: 'absolute',
40
- },
41
- };
42
- this.domElement.parentElement = this.domElement;
43
- this.AddPreRenderCallback = (callback: () => void) => {
44
- callback();
45
- };
46
- this.RemovePreRenderCallback = jest.fn();
47
- this.AddPostRenderCallback = (callback: () => void) => {
48
- callback();
49
- };
50
- this.getViewport = jest.fn();
51
- this.setViewport = jest.fn();
52
- this.autoClear = false;
53
- this.render = jest.fn();
54
- this.StartRenderer = jest.fn();
55
- this.OnResize = jest.fn();
41
+ this.PerformAction = jest.fn().mockReturnValue({
42
+ position: { x: 0, y: 0, z: 0 },
43
+ target: { x: 0, y: 0, z: 0 },
44
+ });
45
+ this.Subscribe = jest.fn((action: string, callback: (data: { id: string }) => void) => {
46
+ callback({ id: 'incorrect id' });
47
+ callback({ id: 'test_uuid' });
48
+ });
49
+ this.DestroyInstance = jest.fn();
56
50
 
57
51
  return this;
58
52
  });
59
53
  });
60
54
 
55
+ jest.mock('../renderer/Renderer.ts', () => {
56
+ return {
57
+ DIVERenderer: jest.fn(function () {
58
+ this.domElement = {
59
+ clientWidth: 800,
60
+ clientHeight: 600,
61
+ style: {
62
+ position: 'absolute',
63
+ },
64
+ };
65
+ this.domElement.parentElement = this.domElement;
66
+ this.AddPreRenderCallback = (callback: () => void) => {
67
+ callback();
68
+ };
69
+ this.RemovePreRenderCallback = jest.fn();
70
+ this.AddPostRenderCallback = (callback: () => void) => {
71
+ callback();
72
+ };
73
+ this.getViewport = jest.fn();
74
+ this.setViewport = jest.fn();
75
+ this.autoClear = false;
76
+ this.render = jest.fn();
77
+ this.StartRenderer = jest.fn();
78
+ this.OnResize = jest.fn();
79
+ this.Dispose = jest.fn();
80
+ return this;
81
+ }),
82
+ }
83
+ });
84
+
61
85
  jest.mock('../scene/Scene.ts', () => {
62
86
  return jest.fn(function () {
63
87
  this.add = jest.fn();
@@ -131,6 +155,7 @@ jest.mock('../toolbox/Toolbox.ts', () => {
131
155
  this.userData = {
132
156
  id: undefined,
133
157
  }
158
+ this.Dispose = jest.fn();
134
159
  this.removeFromParent = jest.fn();
135
160
  return this;
136
161
  });
@@ -152,11 +177,17 @@ jest.mock('../axiscamera/AxisCamera.ts', () => {
152
177
  }
153
178
  this.removeFromParent = jest.fn();
154
179
  this.SetFromCameraMatrix = jest.fn();
180
+ this.Dispose = jest.fn();
155
181
  return this;
156
182
  });
157
183
  });
158
184
 
159
185
  describe('dive/DIVE', () => {
186
+ it('should QuickView', () => {
187
+ const dive = DIVE.QuickView('test_uri');
188
+ expect(dive).toBeDefined();
189
+ });
190
+
160
191
  it('should instantiate', () => {
161
192
  const dive = new DIVE();
162
193
  expect(dive).toBeDefined();
@@ -165,9 +196,21 @@ describe('dive/DIVE', () => {
165
196
  expect(() => (window as any).DIVE.PrintScene()).not.toThrow();
166
197
  });
167
198
 
199
+ it('should dispose', () => {
200
+ let dive = new DIVE();
201
+ expect(() => dive.Dispose()).not.toThrow();
202
+
203
+ const settings = {
204
+ displayAxes: true,
205
+ }
206
+ dive = new DIVE(settings);
207
+ expect(() => dive.Dispose()).not.toThrow();
208
+ });
209
+
168
210
  it('should instantiate with settings', () => {
169
211
  const settings = {
170
212
  autoResize: false,
213
+ displayAxes: true,
171
214
  renderer: {
172
215
  antialias: false,
173
216
  alpha: false,
@@ -209,6 +252,7 @@ describe('dive/DIVE', () => {
209
252
  const dive = new DIVE();
210
253
  dive.Settings = {
211
254
  autoResize: false,
255
+ displayAxes: true,
212
256
  renderer: {
213
257
  antialias: false,
214
258
  alpha: false,
@@ -1,4 +1,5 @@
1
1
  import { update as updateTween } from "@tweenjs/tween.js";
2
+ import { DIVERenderer } from "../renderer/Renderer";
2
3
 
3
4
  /**
4
5
  * Updates all animations.
@@ -8,6 +9,21 @@ import { update as updateTween } from "@tweenjs/tween.js";
8
9
  */
9
10
 
10
11
  export default class DIVEAnimationSystem {
12
+ private _renderer: DIVERenderer;
13
+ private _rendererCallbackId: string;
14
+
15
+ constructor(renderer: DIVERenderer) {
16
+ this._renderer = renderer;
17
+
18
+ this._rendererCallbackId = this._renderer.AddPreRenderCallback(() => {
19
+ this.update();
20
+ })
21
+ }
22
+
23
+ public Dispose(): void {
24
+ this._renderer.RemovePreRenderCallback(this._rendererCallbackId);
25
+ }
26
+
11
27
  public update(): void {
12
28
  updateTween();
13
29
  }
@@ -1,3 +1,4 @@
1
+ import { DIVERenderer } from '../../renderer/Renderer';
1
2
  import DIVEAnimationSystem from '../AnimationSystem';
2
3
 
3
4
  jest.mock('@tweenjs/tween.js', () => {
@@ -6,14 +7,34 @@ jest.mock('@tweenjs/tween.js', () => {
6
7
  }
7
8
  });
8
9
 
10
+ const mockRenderer = {
11
+ render: jest.fn(),
12
+ OnResize: jest.fn(),
13
+ getViewport: jest.fn(),
14
+ setViewport: jest.fn(),
15
+ AddPreRenderCallback: jest.fn((callback) => {
16
+ callback();
17
+ }),
18
+ AddPostRenderCallback: jest.fn((callback) => {
19
+ callback();
20
+ }),
21
+ RemovePreRenderCallback: jest.fn(),
22
+ RemovePostRenderCallback: jest.fn(),
23
+ } as unknown as DIVERenderer;
24
+
9
25
  describe('dive/animation/DIVEAnimationSystem', () => {
10
26
  it('should instantiate', () => {
11
- const anim = new DIVEAnimationSystem();
27
+ const anim = new DIVEAnimationSystem(mockRenderer);
12
28
  expect(anim).toBeDefined();
13
29
  });
14
30
 
15
31
  it('should update', () => {
16
- const anim = new DIVEAnimationSystem();
32
+ const anim = new DIVEAnimationSystem(mockRenderer);
17
33
  expect(() => anim.update()).not.toThrow();
18
34
  });
35
+
36
+ it('should dispose', () => {
37
+ const anim = new DIVEAnimationSystem(mockRenderer);
38
+ expect(() => anim.Dispose()).not.toThrow();
39
+ });
19
40
  });
@@ -1,7 +1,10 @@
1
- import { AxesHelper, Color, Material, Matrix4, OrthographicCamera } from "three";
1
+ import { AxesHelper, Color, Material, Matrix4, OrthographicCamera, Vector4 } from "three";
2
2
  import SpriteText from "three-spritetext";
3
3
  import { COORDINATE_LAYER_MASK } from "../constant/VisibilityLayerMask.ts";
4
4
  import { AxesColorRed, AxesColorGreen, AxesColorBlue, AxesColorRedLetter, AxesColorGreenLetter, AxesColorBlueLetter } from "../constant/AxisHelperColors.ts";
5
+ import { DIVERenderer } from "../renderer/Renderer.ts";
6
+ import DIVEScene from "../scene/Scene.ts";
7
+ import DIVEOrbitControls from "../controls/OrbitControls.ts";
5
8
 
6
9
  /**
7
10
  * Shows the scene axes in the bottom left corner of the screen.
@@ -12,7 +15,12 @@ import { AxesColorRed, AxesColorGreen, AxesColorBlue, AxesColorRedLetter, AxesCo
12
15
  export default class DIVEAxisCamera extends OrthographicCamera {
13
16
  private axesHelper: AxesHelper;
14
17
 
15
- constructor() {
18
+ private _renderer: DIVERenderer;
19
+ private _scene: DIVEScene;
20
+
21
+ private _renderCallbackId: string;
22
+
23
+ constructor(renderer: DIVERenderer, scene: DIVEScene, controls: DIVEOrbitControls) {
16
24
  super(-1, 1, 1, -1, 0.1, 100);
17
25
 
18
26
  this.layers.mask = COORDINATE_LAYER_MASK;
@@ -42,6 +50,36 @@ export default class DIVEAxisCamera extends OrthographicCamera {
42
50
  this.axesHelper.add(z);
43
51
 
44
52
  this.add(this.axesHelper);
53
+
54
+ // attach everything to current scene and render cycle
55
+ this._renderer = renderer;
56
+ this._scene = scene;
57
+ this._scene.add(this);
58
+
59
+ const restoreViewport = new Vector4();
60
+
61
+ this._renderCallbackId = renderer.AddPostRenderCallback(() => {
62
+ const restoreBackground = scene.background;
63
+ scene.background = null;
64
+
65
+ renderer.getViewport(restoreViewport);
66
+ renderer.setViewport(0, 0, 150, 150);
67
+ renderer.autoClear = false;
68
+
69
+ this.SetFromCameraMatrix(controls.object.matrix);
70
+
71
+ renderer.render(scene, this);
72
+
73
+ renderer.setViewport(restoreViewport);
74
+ renderer.autoClear = true;
75
+
76
+ scene.background = restoreBackground;
77
+ });
78
+ }
79
+
80
+ public Dispose(): void {
81
+ this._renderer.RemovePostRenderCallback(this._renderCallbackId);
82
+ this._scene.remove(this);
45
83
  }
46
84
 
47
85
  public SetFromCameraMatrix(matrix: Matrix4): void {
@@ -1,5 +1,63 @@
1
- import { Matrix4 } from 'three';
1
+ import { AxesHelper, Matrix4, OrthographicCamera, Vector4 } from 'three';
2
2
  import DIVEAxisCamera from '../AxisCamera';
3
+ import { DIVERenderer } from '../../renderer/Renderer';
4
+ import DIVEScene from '../../scene/Scene';
5
+ import DIVEOrbitControls from '../../controls/OrbitControls';
6
+
7
+ jest.mock('three', () => {
8
+ return {
9
+ Vector4: jest.fn(),
10
+ Color: jest.fn(function () {
11
+ this.getHexString = jest.fn().mockReturnValue('ffffff');
12
+ return this;
13
+ }),
14
+ Matrix4: jest.fn(function () {
15
+ this.extractRotation = jest.fn(() => { return this; });
16
+ this.invert = jest.fn(() => { return this; });
17
+ this.elements = [
18
+ 1, 0, 0, 0,
19
+ 0, 1, 0, 0,
20
+ 0, 0, 1, 0,
21
+ 0, 0, 0, 1,
22
+ ];
23
+ return this;
24
+ }),
25
+ OrthographicCamera: jest.fn(function () {
26
+
27
+ this.isObject3D = true;
28
+ this.parent = null;
29
+ this.dispatchEvent = jest.fn();
30
+ this.layers = {
31
+ mask: 0,
32
+ };
33
+ this.position = {
34
+ set: jest.fn(),
35
+ };
36
+ this.add = jest.fn();
37
+ return this;
38
+ }),
39
+ AxesHelper: jest.fn(function () {
40
+ this.isObject3D = true;
41
+ this.parent = null;
42
+ this.dispatchEvent = jest.fn();
43
+ this.layers = {
44
+ mask: 0,
45
+ };
46
+ this.position = {
47
+ set: jest.fn(),
48
+ };
49
+ this.add = jest.fn();
50
+ this.material = {
51
+ depthTest: false,
52
+ };
53
+ this.setColors = jest.fn();
54
+ this.rotation = {
55
+ setFromRotationMatrix: jest.fn(),
56
+ }
57
+ return this;
58
+ }),
59
+ }
60
+ });
3
61
 
4
62
  jest.mock('three-spritetext', () => {
5
63
  return jest.fn(() => {
@@ -19,10 +77,122 @@ jest.mock('three-spritetext', () => {
19
77
  )
20
78
  });
21
79
 
80
+ const mockRenderer = {
81
+ render: jest.fn(),
82
+ OnResize: jest.fn(),
83
+ getViewport: jest.fn(),
84
+ setViewport: jest.fn(),
85
+ AddPostRenderCallback: jest.fn((callback) => {
86
+ callback();
87
+ }),
88
+ RemovePostRenderCallback: jest.fn(),
89
+ } as unknown as DIVERenderer;
90
+
91
+ const mockScene = {
92
+ add: jest.fn(),
93
+ remove: jest.fn(),
94
+ SetBackground: jest.fn(),
95
+ AddSceneObject: jest.fn(),
96
+ UpdateSceneObject: jest.fn(),
97
+ DeleteSceneObject: jest.fn(),
98
+ PlaceOnFloor: jest.fn(),
99
+ GetSceneObject: jest.fn(),
100
+ background: {
101
+ getHexString: jest.fn().mockReturnValue('ffffff'),
102
+ },
103
+ Root: {
104
+ Floor: {
105
+ isFloor: true,
106
+ visible: true,
107
+ material: {
108
+ color: {
109
+ getHexString: jest.fn().mockReturnValue('ffffff'),
110
+ },
111
+ },
112
+ SetVisibility: jest.fn(),
113
+ SetColor: jest.fn(),
114
+ },
115
+ Grid: {
116
+ SetVisibility: jest.fn(),
117
+ },
118
+ },
119
+ } as unknown as DIVEScene;
120
+
121
+ const mockController = {
122
+ enableDamping: true,
123
+ dampingFactor: 0.25,
124
+ enableZoom: true,
125
+ enablePan: true,
126
+ minPolarAngle: 0,
127
+ maxPolarAngle: Math.PI,
128
+ minDistance: 0,
129
+ maxDistance: Infinity,
130
+ rotateSpeed: 0.5,
131
+ panSpeed: 0.5,
132
+ zoomSpeed: 0.5,
133
+ keyPanSpeed: 0.5,
134
+ screenSpacePanning: true,
135
+ autoRotate: false,
136
+ autoRotateSpeed: 2.0,
137
+ enableKeys: true,
138
+ keys: {
139
+ LEFT: 37,
140
+ UP: 38,
141
+ RIGHT: 39,
142
+ BOTTOM: 40,
143
+ },
144
+ mouseButtons: {
145
+ LEFT: 0,
146
+ MIDDLE: 1,
147
+ RIGHT: 2,
148
+ },
149
+ target: {
150
+ x: 4,
151
+ y: 5,
152
+ z: 6,
153
+ set: jest.fn(),
154
+ clone: jest.fn().mockReturnValue({ x: 4, y: 5, z: 6 }),
155
+ copy: jest.fn(),
156
+ },
157
+ update: jest.fn(),
158
+ dispose: jest.fn(),
159
+ ZoomIn: jest.fn(),
160
+ ZoomOut: jest.fn(),
161
+ object: {
162
+ position: {
163
+ x: 1,
164
+ y: 2,
165
+ z: 3,
166
+ clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3 }),
167
+ copy: jest.fn(),
168
+ },
169
+ quaternion: {
170
+ x: 1,
171
+ y: 2,
172
+ z: 3,
173
+ w: 4,
174
+ clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3, w: 4 }),
175
+ copy: jest.fn(),
176
+ },
177
+ SetCameraLayer: jest.fn(),
178
+ OnResize: jest.fn(),
179
+ layers: {
180
+ mask: 1,
181
+ },
182
+ },
183
+ MoveTo: jest.fn(),
184
+ RevertLast: jest.fn(),
185
+ } as unknown as DIVEOrbitControls;
186
+
187
+ let textAxisCamera: DIVEAxisCamera;
188
+
22
189
  describe('dive/axiscamera/DIVEAxisCamera', () => {
190
+ beforeEach(() => {
191
+ textAxisCamera = new DIVEAxisCamera(mockRenderer, mockScene, mockController);
192
+ });
193
+
23
194
  it('should instantiate', () => {
24
- const cam = new DIVEAxisCamera();
25
- expect(cam).toBeDefined();
195
+ expect(textAxisCamera).toBeDefined();
26
196
  });
27
197
 
28
198
  it('should set rotation from Matrix4', () => {
@@ -35,7 +205,10 @@ describe('dive/axiscamera/DIVEAxisCamera', () => {
35
205
  0, 0, 0, 1,
36
206
  ],
37
207
  } as Matrix4;
38
- const cam = new DIVEAxisCamera();
39
- cam.SetFromCameraMatrix(matrix);
208
+ textAxisCamera.SetFromCameraMatrix(matrix);
209
+ });
210
+
211
+ it('should dispose', () => {
212
+ textAxisCamera.Dispose();
40
213
  });
41
214
  });
@@ -1,13 +1,17 @@
1
- import { Color, MeshStandardMaterial, MathUtils } from "three";
2
- import DIVEScene from "../scene/Scene.ts";
3
1
  import { Actions } from "./actions/index.ts";
4
- import { COMLight, COMModel, COMEntity, COMPov } from "./types.ts";
5
- import DIVEToolbox from "../toolbox/Toolbox.ts";
6
- import DIVEMediaCreator from "../mediacreator/MediaCreator.ts";
7
- import DIVEOrbitControls from "../controls/OrbitControls.ts";
8
- import { DIVESelectable } from "../interface/Selectable.ts";
9
- import DIVESelectTool from "../toolbox/select/SelectTool.ts";
2
+ import { generateUUID } from 'three/src/math/MathUtils';
3
+
4
+ // type imports
5
+ import { type Color, type MeshStandardMaterial } from "three";
6
+ import { type COMLight, type COMModel, type COMEntity, type COMPov } from "./types.ts";
7
+ import type DIVEScene from "../scene/Scene.ts";
8
+ import type DIVEToolbox from "../toolbox/Toolbox.ts";
9
+ import type DIVEOrbitControls from "../controls/OrbitControls.ts";
10
10
  import type DIVEModel from "../model/Model.ts";
11
+ import { type DIVEMediaCreator } from "../mediacreator/MediaCreator.ts";
12
+ import { type DIVERenderer } from "../renderer/Renderer.ts";
13
+ import { type DIVESelectable } from "../interface/Selectable.ts";
14
+ import { isSelectTool } from "../toolbox/select/SelectTool.ts";
11
15
 
12
16
  type EventListener<Action extends keyof Actions> = (payload: Actions[Action]['PAYLOAD']) => void;
13
17
 
@@ -41,22 +45,32 @@ export default class DIVECommunication {
41
45
  }
42
46
 
43
47
  private id: string;
48
+ private renderer: DIVERenderer;
44
49
  private scene: DIVEScene;
45
50
  private controller: DIVEOrbitControls;
46
51
  private toolbox: DIVEToolbox;
47
- private mediaGenerator: DIVEMediaCreator;
52
+
53
+ private _mediaGenerator: DIVEMediaCreator | null;
54
+ private get mediaGenerator(): DIVEMediaCreator {
55
+ if (!this._mediaGenerator) {
56
+ const DIVEMediaCreator = require('../mediacreator/MediaCreator.ts').default as typeof import('../mediacreator/MediaCreator.ts').DIVEMediaCreator;
57
+ this._mediaGenerator = new DIVEMediaCreator(this.renderer, this.scene, this.controller);
58
+ }
59
+ return this._mediaGenerator;
60
+ }
48
61
 
49
62
  private registered: Map<string, COMEntity> = new Map();
50
63
 
51
64
  // private listeners: { [key: string]: EventListener[] } = {};
52
65
  private listeners: Map<keyof Actions, EventListener<keyof Actions>[]> = new Map();
53
66
 
54
- constructor(scene: DIVEScene, controls: DIVEOrbitControls, toolbox: DIVEToolbox, mediaGenerator: DIVEMediaCreator) {
55
- this.id = MathUtils.generateUUID();
67
+ constructor(renderer: DIVERenderer, scene: DIVEScene, controls: DIVEOrbitControls, toolbox: DIVEToolbox) {
68
+ this.id = generateUUID();
69
+ this.renderer = renderer;
56
70
  this.scene = scene;
57
71
  this.controller = controls;
58
72
  this.toolbox = toolbox;
59
- this.mediaGenerator = mediaGenerator;
73
+ this._mediaGenerator = null;
60
74
 
61
75
  DIVECommunication.__instances.push(this);
62
76
  }
@@ -132,6 +146,10 @@ export default class DIVECommunication {
132
146
  returnValue = this.resetCamera(payload as Actions['RESET_CAMERA']['PAYLOAD']);
133
147
  break;
134
148
  }
149
+ case 'COMPUTE_ENCOMPASSING_VIEW': {
150
+ returnValue = this.computeEncompassingView(payload as Actions['COMPUTE_ENCOMPASSING_VIEW']['PAYLOAD']);
151
+ break;
152
+ }
135
153
  case 'SET_CAMERA_LAYER': {
136
154
  returnValue = this.setCameraLayer(payload as Actions['SET_CAMERA_LAYER']['PAYLOAD']);
137
155
  break;
@@ -276,8 +294,10 @@ export default class DIVECommunication {
276
294
 
277
295
  if (!('isSelectable' in sceneObject)) return false;
278
296
 
279
- this.toolbox.UseTool('select');
280
- (this.toolbox.GetActiveTool() as DIVESelectTool).AttachGizmo(sceneObject as DIVESelectable);
297
+ const activeTool = this.toolbox.GetActiveTool();
298
+ if (activeTool && isSelectTool(activeTool)) {
299
+ activeTool.AttachGizmo(sceneObject as DIVESelectable);
300
+ }
281
301
 
282
302
  // copy object to payload to use later
283
303
  Object.assign(payload, object);
@@ -294,8 +314,10 @@ export default class DIVECommunication {
294
314
 
295
315
  if (!('isSelectable' in sceneObject)) return false;
296
316
 
297
- this.toolbox.UseTool('select');
298
- (this.toolbox.GetActiveTool() as DIVESelectTool).DetachGizmo();
317
+ const activeTool = this.toolbox.GetActiveTool();
318
+ if (activeTool && isSelectTool(activeTool)) {
319
+ activeTool.DetachGizmo();
320
+ }
299
321
 
300
322
  // copy object to payload to use later
301
323
  Object.assign(payload, object);
@@ -372,6 +394,15 @@ export default class DIVECommunication {
372
394
  return true;
373
395
  }
374
396
 
397
+ private computeEncompassingView(payload: Actions['COMPUTE_ENCOMPASSING_VIEW']['PAYLOAD']): Actions['COMPUTE_ENCOMPASSING_VIEW']['RETURN'] {
398
+ const sceneBB = this.scene.ComputeSceneBB();
399
+
400
+ const transform = this.controller.ComputeEncompassingView(sceneBB);
401
+ Object.assign(payload, transform);
402
+
403
+ return transform;
404
+ }
405
+
375
406
  private zoomCamera(payload: Actions['ZOOM_CAMERA']['PAYLOAD']): Actions['ZOOM_CAMERA']['RETURN'] {
376
407
  if (payload.direction === 'IN') this.controller.ZoomIn(payload.by);
377
408
  if (payload.direction === 'OUT') this.controller.ZoomOut(payload.by);
@@ -398,6 +429,8 @@ export default class DIVECommunication {
398
429
  if (payload.name !== undefined) this.scene.name = payload.name;
399
430
  if (payload.backgroundColor !== undefined) this.scene.SetBackground(payload.backgroundColor);
400
431
 
432
+ if (payload.gridEnabled !== undefined) this.scene.Root.Grid.SetVisibility(payload.gridEnabled);
433
+
401
434
  if (payload.floorEnabled !== undefined) this.scene.Root.Floor.SetVisibility(payload.floorEnabled);
402
435
  if (payload.floorColor !== undefined) this.scene.Root.Floor.SetColor(payload.floorColor);
403
436
 
@@ -406,6 +439,7 @@ export default class DIVECommunication {
406
439
  // TODO optmize this
407
440
  payload.name = this.scene.name;
408
441
  payload.backgroundColor = '#' + (this.scene.background as Color).getHexString();
442
+ payload.gridEnabled = this.scene.Root.Grid.visible;
409
443
  payload.floorEnabled = this.scene.Root.Floor.visible;
410
444
  payload.floorColor = '#' + (this.scene.Root.Floor.material as MeshStandardMaterial).color.getHexString();
411
445