@shopware-ag/dive 1.4.2 → 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 (46) hide show
  1. package/README.md +38 -24
  2. package/build/dive.cjs +734 -492
  3. package/build/dive.cjs.map +1 -1
  4. package/build/dive.d.cts +182 -113
  5. package/build/dive.d.ts +182 -113
  6. package/build/dive.js +733 -478
  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 +59 -16
  15. package/src/com/__test__/Communication.test.ts +83 -24
  16. package/src/com/actions/camera/computeencompassingview.ts +9 -0
  17. package/src/com/actions/index.ts +4 -0
  18. package/src/com/actions/scene/updatescene.ts +1 -0
  19. package/src/com/actions/toolbox/transform/setgizmovisible.ts +4 -0
  20. package/src/controls/OrbitControls.ts +14 -2
  21. package/src/controls/__test__/OrbitControls.test.ts +31 -4
  22. package/src/dive.ts +93 -33
  23. package/src/grid/Grid.ts +4 -0
  24. package/src/grid/__test__/Grid.test.ts +7 -0
  25. package/src/interface/Selectable.ts +17 -0
  26. package/src/interface/__test__/Interfaces.test.ts +18 -0
  27. package/src/mediacreator/MediaCreator.ts +2 -2
  28. package/src/mediacreator/__test__/MediaCreator.test.ts +12 -10
  29. package/src/model/Model.ts +6 -0
  30. package/src/model/__test__/Model.test.ts +9 -0
  31. package/src/renderer/Renderer.ts +7 -1
  32. package/src/renderer/__test__/Renderer.test.ts +14 -5
  33. package/src/scene/Scene.ts +8 -2
  34. package/src/scene/__test__/Scene.test.ts +6 -0
  35. package/src/scene/root/Root.ts +11 -1
  36. package/src/scene/root/__test__/Root.test.ts +68 -2
  37. package/src/scene/root/modelroot/ModelRoot.ts +1 -1
  38. package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +1 -0
  39. package/src/toolbox/BaseTool.ts +3 -3
  40. package/src/toolbox/Toolbox.ts +57 -37
  41. package/src/toolbox/__test__/BaseTool.test.ts +49 -7
  42. package/src/toolbox/__test__/Toolbox.test.ts +43 -40
  43. package/src/toolbox/select/SelectTool.ts +18 -28
  44. package/src/toolbox/select/__test__/SelectTool.test.ts +27 -8
  45. package/src/toolbox/transform/TransformTool.ts +16 -1
  46. package/src/toolbox/transform/__test__/TransformTool.test.ts +34 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.4.2",
3
+ "version": "1.6.0",
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;
@@ -144,6 +162,10 @@ export default class DIVECommunication {
144
162
  returnValue = this.setGizmoMode(payload as Actions['SET_GIZMO_MODE']['PAYLOAD']);
145
163
  break;
146
164
  }
165
+ case 'SET_GIZMO_VISIBILITY': {
166
+ returnValue = this.setGizmoVisibility(payload as Actions['SET_GIZMO_VISIBILITY']['PAYLOAD']);
167
+ break;
168
+ }
147
169
  case 'MODEL_LOADED': {
148
170
  returnValue = this.modelLoaded(payload as Actions['MODEL_LOADED']['PAYLOAD']);
149
171
  break;
@@ -272,8 +294,10 @@ export default class DIVECommunication {
272
294
 
273
295
  if (!('isSelectable' in sceneObject)) return false;
274
296
 
275
- this.toolbox.UseTool('select');
276
- (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
+ }
277
301
 
278
302
  // copy object to payload to use later
279
303
  Object.assign(payload, object);
@@ -290,8 +314,10 @@ export default class DIVECommunication {
290
314
 
291
315
  if (!('isSelectable' in sceneObject)) return false;
292
316
 
293
- this.toolbox.UseTool('select');
294
- (this.toolbox.GetActiveTool() as DIVESelectTool).DetachGizmo();
317
+ const activeTool = this.toolbox.GetActiveTool();
318
+ if (activeTool && isSelectTool(activeTool)) {
319
+ activeTool.DetachGizmo();
320
+ }
295
321
 
296
322
  // copy object to payload to use later
297
323
  Object.assign(payload, object);
@@ -368,6 +394,15 @@ export default class DIVECommunication {
368
394
  return true;
369
395
  }
370
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
+
371
406
  private zoomCamera(payload: Actions['ZOOM_CAMERA']['PAYLOAD']): Actions['ZOOM_CAMERA']['RETURN'] {
372
407
  if (payload.direction === 'IN') this.controller.ZoomIn(payload.by);
373
408
  if (payload.direction === 'OUT') this.controller.ZoomOut(payload.by);
@@ -380,6 +415,11 @@ export default class DIVECommunication {
380
415
  return true;
381
416
  }
382
417
 
418
+ private setGizmoVisibility(payload: Actions['SET_GIZMO_VISIBILITY']['PAYLOAD']): Actions['SET_GIZMO_VISIBILITY']['RETURN'] {
419
+ this.toolbox.SetGizmoVisibility(payload);
420
+ return payload;
421
+ }
422
+
383
423
  private modelLoaded(payload: Actions['MODEL_LOADED']['PAYLOAD']): Actions['MODEL_LOADED']['RETURN'] {
384
424
  (this.registered.get(payload.id) as COMModel).loaded = true;
385
425
  return true;
@@ -389,6 +429,8 @@ export default class DIVECommunication {
389
429
  if (payload.name !== undefined) this.scene.name = payload.name;
390
430
  if (payload.backgroundColor !== undefined) this.scene.SetBackground(payload.backgroundColor);
391
431
 
432
+ if (payload.gridEnabled !== undefined) this.scene.Root.Grid.SetVisibility(payload.gridEnabled);
433
+
392
434
  if (payload.floorEnabled !== undefined) this.scene.Root.Floor.SetVisibility(payload.floorEnabled);
393
435
  if (payload.floorColor !== undefined) this.scene.Root.Floor.SetColor(payload.floorColor);
394
436
 
@@ -397,6 +439,7 @@ export default class DIVECommunication {
397
439
  // TODO optmize this
398
440
  payload.name = this.scene.name;
399
441
  payload.backgroundColor = '#' + (this.scene.background as Color).getHexString();
442
+ payload.gridEnabled = this.scene.Root.Grid.visible;
400
443
  payload.floorEnabled = this.scene.Root.Floor.visible;
401
444
  payload.floorColor = '#' + (this.scene.Root.Floor.material as MeshStandardMaterial).color.getHexString();
402
445