@shopware-ag/dive 1.14.0 → 1.15.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.
- package/build/dive.cjs +109 -160
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +19 -36
- package/build/dive.d.ts +19 -36
- package/build/dive.js +67 -118
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/group/Group.ts +13 -42
- package/src/group/__test__/Group.test.ts +9 -17
- package/src/model/Model.ts +8 -58
- package/src/model/__test__/Model.test.ts +1 -56
- package/src/node/Node.ts +58 -0
- package/src/node/__test__/Node.test.ts +229 -0
- package/src/primitive/Primitive.ts +3 -49
- package/src/primitive/__test__/Primitive.test.ts +0 -55
package/package.json
CHANGED
package/src/group/Group.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { type DIVESelectable } from "../interface/Selectable";
|
|
4
|
-
import { type DIVESceneObject } from "../types";
|
|
1
|
+
import { BoxGeometry, Mesh, MeshBasicMaterial, Vector3 } from "three";
|
|
2
|
+
import { DIVENode } from "../node/Node";
|
|
5
3
|
import { DIVECommunication } from "../com/Communication";
|
|
4
|
+
import { type DIVESceneObject } from "../types";
|
|
6
5
|
|
|
7
|
-
export class DIVEGroup extends
|
|
6
|
+
export class DIVEGroup extends DIVENode {
|
|
8
7
|
readonly isDIVEGroup: true = true;
|
|
9
|
-
readonly isSelectable: true = true;
|
|
10
|
-
readonly isMoveable: true = true;
|
|
11
8
|
|
|
12
|
-
private _bb: Box3;
|
|
13
9
|
private _boxMesh: Mesh;
|
|
14
10
|
|
|
15
11
|
constructor() {
|
|
@@ -17,32 +13,11 @@ export class DIVEGroup extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
17
13
|
|
|
18
14
|
this.name = 'DIVEGroup';
|
|
19
15
|
|
|
20
|
-
this._bb = new Box3();
|
|
21
|
-
|
|
22
16
|
this._boxMesh = new Mesh(new BoxGeometry(0, 0, 0), new MeshBasicMaterial({ color: 0xff0000, wireframe: true }));
|
|
23
17
|
this._boxMesh.visible = false;
|
|
24
18
|
this.add(this._boxMesh);
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
public SetPosition(position: Vector3Like): void {
|
|
28
|
-
this.position.set(position.x, position.y, position.z);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public SetRotation(rotation: Vector3Like): void {
|
|
32
|
-
this.rotation.setFromVector3(new Vector3(rotation.x, rotation.y, rotation.z));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public SetScale(scale: Vector3Like): void {
|
|
36
|
-
this.scale.set(scale.x, scale.y, scale.z);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public SetVisibility(visible: boolean): void {
|
|
40
|
-
this.traverse((child) => {
|
|
41
|
-
if (child.uuid === this._boxMesh.uuid) return;
|
|
42
|
-
child.visible = visible;
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
21
|
public SetBoundingBoxVisibility(visible: boolean): void {
|
|
47
22
|
this._boxMesh.visible = visible;
|
|
48
23
|
}
|
|
@@ -99,28 +74,24 @@ export class DIVEGroup extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
99
74
|
* @returns {Vector3} The new center of the bounding box.
|
|
100
75
|
*/
|
|
101
76
|
private updateBB(): Vector3 {
|
|
102
|
-
this.
|
|
77
|
+
this._boundingBox.makeEmpty();
|
|
103
78
|
this.children.forEach((child) => {
|
|
104
79
|
if (child.uuid === this._boxMesh.uuid) return;
|
|
105
|
-
this.
|
|
80
|
+
this._boundingBox.expandByObject(child);
|
|
106
81
|
});
|
|
107
82
|
|
|
108
|
-
return this.
|
|
83
|
+
return this._boundingBox.getCenter(new Vector3());
|
|
109
84
|
}
|
|
110
85
|
|
|
111
86
|
private updateBoxMesh(): void {
|
|
112
|
-
this._boxMesh.
|
|
87
|
+
this._boxMesh.quaternion.copy(this.quaternion.clone().invert());
|
|
88
|
+
this._boxMesh.scale.set(1 / this.scale.x, 1 / this.scale.y, 1 / this.scale.z);
|
|
89
|
+
this._boxMesh.geometry = new BoxGeometry(this._boundingBox.max.x - this._boundingBox.min.x, this._boundingBox.max.y - this._boundingBox.min.y, this._boundingBox.max.z - this._boundingBox.min.z);
|
|
113
90
|
}
|
|
114
91
|
|
|
115
92
|
public onMove(): void {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
public onSelect(): void {
|
|
120
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
public onDeselect(): void {
|
|
124
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
|
|
93
|
+
super.onMove();
|
|
94
|
+
this.updateBB();
|
|
95
|
+
this.updateBoxMesh();
|
|
125
96
|
}
|
|
126
97
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
|
2
1
|
import { DIVECommunication } from "../../com/Communication";
|
|
3
2
|
import { DIVEGroup } from "../Group";
|
|
4
3
|
|
|
@@ -31,22 +30,6 @@ describe('dive/group/DIVEGroup', () => {
|
|
|
31
30
|
expect(group).toBeDefined();
|
|
32
31
|
});
|
|
33
32
|
|
|
34
|
-
it('should set position', () => {
|
|
35
|
-
expect(() => group.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should set rotation', () => {
|
|
39
|
-
expect(() => group.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should set scale', () => {
|
|
43
|
-
expect(() => group.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should set visibility', () => {
|
|
47
|
-
expect(() => group.SetVisibility(true)).not.toThrow();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
33
|
it('should set bounding box visibility', () => {
|
|
51
34
|
expect(() => group.SetBoundingBoxVisibility(true)).not.toThrow();
|
|
52
35
|
});
|
|
@@ -97,4 +80,13 @@ describe('dive/group/DIVEGroup', () => {
|
|
|
97
80
|
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
98
81
|
expect(() => group.onDeselect()).not.toThrow();
|
|
99
82
|
});
|
|
83
|
+
|
|
84
|
+
it('should onMove', () => {
|
|
85
|
+
group.userData.id = 'something';
|
|
86
|
+
|
|
87
|
+
expect(() => group.onMove()).not.toThrow();
|
|
88
|
+
|
|
89
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
90
|
+
expect(() => group.onMove()).not.toThrow();
|
|
91
|
+
});
|
|
100
92
|
});
|
package/src/model/Model.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DIVESelectable } from '../interface/Selectable';
|
|
1
|
+
import { Mesh, MeshStandardMaterial, Raycaster, Vector3 } from 'three';
|
|
3
2
|
import { PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask';
|
|
4
|
-
import { DIVEMoveable } from '../interface/Moveable';
|
|
5
3
|
import { DIVECommunication } from '../com/Communication';
|
|
6
|
-
import type { GLTF
|
|
4
|
+
import type { GLTF } from 'three/examples/jsm/Addons.js';
|
|
7
5
|
import { findSceneRecursive } from '../helper/findSceneRecursive/findSceneRecursive';
|
|
8
6
|
import { type COMMaterial } from '../com/types';
|
|
7
|
+
import { DIVENode } from '../node/Node';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* A basic model class.
|
|
@@ -17,26 +16,12 @@ import { type COMMaterial } from '../com/types';
|
|
|
17
16
|
* @module
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
|
-
export class DIVEModel extends
|
|
19
|
+
export class DIVEModel extends DIVENode {
|
|
21
20
|
readonly isDIVEModel: true = true;
|
|
22
|
-
readonly isSelectable: true = true;
|
|
23
|
-
readonly isMoveable: true = true;
|
|
24
|
-
|
|
25
|
-
public gizmo: TransformControls | null = null;
|
|
26
|
-
|
|
27
|
-
private boundingBox: Box3;
|
|
28
21
|
|
|
29
22
|
private _mesh: Mesh | null = null;
|
|
30
23
|
private _material: MeshStandardMaterial | null = null;
|
|
31
24
|
|
|
32
|
-
constructor() {
|
|
33
|
-
super();
|
|
34
|
-
|
|
35
|
-
this.layers.mask = PRODUCT_LAYER_MASK;
|
|
36
|
-
|
|
37
|
-
this.boundingBox = new Box3();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
25
|
public SetModel(gltf: GLTF): void {
|
|
41
26
|
this.clear();
|
|
42
27
|
|
|
@@ -45,7 +30,7 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
45
30
|
child.receiveShadow = true;
|
|
46
31
|
|
|
47
32
|
child.layers.mask = this.layers.mask;
|
|
48
|
-
this.
|
|
33
|
+
this._boundingBox.expandByObject(child);
|
|
49
34
|
|
|
50
35
|
// only search for first mesh for now
|
|
51
36
|
if (!this._mesh && 'isMesh' in child) {
|
|
@@ -63,24 +48,6 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
63
48
|
this.add(gltf.scene);
|
|
64
49
|
}
|
|
65
50
|
|
|
66
|
-
public SetPosition(position: Vector3Like): void {
|
|
67
|
-
this.position.set(position.x, position.y, position.z);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public SetRotation(rotation: Vector3Like): void {
|
|
71
|
-
this.rotation.setFromVector3(new Vector3(rotation.x, rotation.y, rotation.z));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
public SetScale(scale: Vector3Like): void {
|
|
75
|
-
this.scale.set(scale.x, scale.y, scale.z);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public SetVisibility(visible: boolean): void {
|
|
79
|
-
this.traverse((child) => {
|
|
80
|
-
child.visible = visible;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
51
|
public SetMaterial(material: Partial<COMMaterial>): void {
|
|
85
52
|
// if there is no material, create a new one
|
|
86
53
|
if (!this._material) {
|
|
@@ -142,13 +109,8 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
142
109
|
}
|
|
143
110
|
}
|
|
144
111
|
|
|
145
|
-
public SetToWorldOrigin(): void {
|
|
146
|
-
this.position.set(0, 0, 0);
|
|
147
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
148
|
-
}
|
|
149
|
-
|
|
150
112
|
public PlaceOnFloor(): void {
|
|
151
|
-
this.position.y = -this.
|
|
113
|
+
this.position.y = -this._boundingBox.min.y * this.scale.y;
|
|
152
114
|
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
153
115
|
}
|
|
154
116
|
|
|
@@ -159,8 +121,8 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
159
121
|
}
|
|
160
122
|
|
|
161
123
|
// calculate the bottom center of the bounding box
|
|
162
|
-
const bottomY = this.
|
|
163
|
-
const bbBottomCenter = this.localToWorld(this.
|
|
124
|
+
const bottomY = this._boundingBox.min.y * this.scale.y;
|
|
125
|
+
const bbBottomCenter = this.localToWorld(this._boundingBox.getCenter(new Vector3()).multiply(this.scale));
|
|
164
126
|
bbBottomCenter.y = bottomY + this.position.y;
|
|
165
127
|
|
|
166
128
|
// set up raycaster and raycast all scene objects (product layer)
|
|
@@ -184,16 +146,4 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
|
|
|
184
146
|
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
185
147
|
}
|
|
186
148
|
}
|
|
187
|
-
|
|
188
|
-
public onMove(): void {
|
|
189
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
public onSelect(): void {
|
|
193
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public onDeselect(): void {
|
|
197
|
-
DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
|
|
198
|
-
}
|
|
199
149
|
}
|
|
@@ -214,34 +214,6 @@ describe('dive/model/DIVEModel', () => {
|
|
|
214
214
|
expect(() => model.SetModel(gltf)).not.toThrow();
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
-
it('should set position', () => {
|
|
218
|
-
expect(() => model.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('should set rotation', () => {
|
|
222
|
-
expect(() => model.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('should set scale', () => {
|
|
226
|
-
expect(() => model.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('should set visibility', () => {
|
|
230
|
-
expect(() => model.SetVisibility(true)).not.toThrow();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('should set to world origin', () => {
|
|
234
|
-
model.userData.id = 'something';
|
|
235
|
-
|
|
236
|
-
expect(() => model.SetToWorldOrigin()).not.toThrow();
|
|
237
|
-
expect(model.position.x).toBe(0);
|
|
238
|
-
expect(model.position.y).toBe(0);
|
|
239
|
-
expect(model.position.z).toBe(0);
|
|
240
|
-
|
|
241
|
-
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
242
|
-
expect(() => model.SetToWorldOrigin()).not.toThrow();
|
|
243
|
-
});
|
|
244
|
-
|
|
245
217
|
it('should place on floor', () => {
|
|
246
218
|
model.userData.id = 'something';
|
|
247
219
|
|
|
@@ -265,7 +237,7 @@ describe('dive/model/DIVEModel', () => {
|
|
|
265
237
|
|
|
266
238
|
model.userData.id = 'something';
|
|
267
239
|
model.position.set(0, 4, 0);
|
|
268
|
-
model['
|
|
240
|
+
model['_boundingBox'] = {
|
|
269
241
|
min: new Vector3(-size.x / 2, -size.y / 2, -size.z / 2),
|
|
270
242
|
max: new Vector3(size.x / 2, size.y / 2, size.z / 2),
|
|
271
243
|
getCenter: jest.fn(() => {
|
|
@@ -315,33 +287,6 @@ describe('dive/model/DIVEModel', () => {
|
|
|
315
287
|
|
|
316
288
|
});
|
|
317
289
|
|
|
318
|
-
it('should onMove', () => {
|
|
319
|
-
model.userData.id = 'something';
|
|
320
|
-
|
|
321
|
-
expect(() => model.onMove()).not.toThrow();
|
|
322
|
-
|
|
323
|
-
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
324
|
-
expect(() => model.onMove()).not.toThrow();
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it('should onSelect', () => {
|
|
328
|
-
model.userData.id = 'something';
|
|
329
|
-
|
|
330
|
-
expect(() => model.onSelect()).not.toThrow();
|
|
331
|
-
|
|
332
|
-
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
333
|
-
expect(() => model.onSelect()).not.toThrow();
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it('should onDeselect', () => {
|
|
337
|
-
model.userData.id = 'something';
|
|
338
|
-
|
|
339
|
-
expect(() => model.onDeselect()).not.toThrow();
|
|
340
|
-
|
|
341
|
-
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
342
|
-
expect(() => model.onDeselect()).not.toThrow();
|
|
343
|
-
});
|
|
344
|
-
|
|
345
290
|
it('should set material', () => {
|
|
346
291
|
// apply invalid material should not crash
|
|
347
292
|
expect(() => model.SetMaterial({} as COMMaterial)).not.toThrow();
|
package/src/node/Node.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Box3, Object3D, type Vector3Like } from "three";
|
|
2
|
+
import { PRODUCT_LAYER_MASK } from "../constant/VisibilityLayerMask";
|
|
3
|
+
import { DIVECommunication } from "../com/Communication";
|
|
4
|
+
|
|
5
|
+
import { type DIVEMoveable } from "../interface/Moveable";
|
|
6
|
+
import { type DIVESelectable } from "../interface/Selectable";
|
|
7
|
+
import { type TransformControls } from "three/examples/jsm/controls/TransformControls";
|
|
8
|
+
|
|
9
|
+
export class DIVENode extends Object3D implements DIVESelectable, DIVEMoveable {
|
|
10
|
+
readonly isDIVENode: true = true;
|
|
11
|
+
readonly isSelectable: true = true;
|
|
12
|
+
readonly isMoveable: true = true;
|
|
13
|
+
|
|
14
|
+
public gizmo: TransformControls | null = null;
|
|
15
|
+
|
|
16
|
+
protected _boundingBox: Box3;
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
|
|
21
|
+
this.layers.mask = PRODUCT_LAYER_MASK;
|
|
22
|
+
|
|
23
|
+
this._boundingBox = new Box3();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public SetPosition(position: Vector3Like): void {
|
|
27
|
+
this.position.set(position.x, position.y, position.z);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public SetRotation(rotation: Vector3Like): void {
|
|
31
|
+
this.rotation.set(rotation.x, rotation.y, rotation.z);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public SetScale(scale: Vector3Like): void {
|
|
35
|
+
this.scale.set(scale.x, scale.y, scale.z);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public SetVisibility(visible: boolean): void {
|
|
39
|
+
this.visible = visible;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public SetToWorldOrigin(): void {
|
|
43
|
+
this.position.set(0, 0, 0);
|
|
44
|
+
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public onMove(): void {
|
|
48
|
+
DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public onSelect(): void {
|
|
52
|
+
DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public onDeselect(): void {
|
|
56
|
+
DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { DIVENode } from '../Node';
|
|
2
|
+
import { DIVECommunication } from '../../com/Communication';
|
|
3
|
+
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
4
|
+
import { Vector3, Box3, Mesh, Color, Euler } from 'three';
|
|
5
|
+
|
|
6
|
+
const intersectObjectsMock = jest.fn();
|
|
7
|
+
|
|
8
|
+
jest.mock('three', () => {
|
|
9
|
+
return {
|
|
10
|
+
Vector3: jest.fn(function (x: number, y: number, z: number) {
|
|
11
|
+
this.x = x;
|
|
12
|
+
this.y = y;
|
|
13
|
+
this.z = z;
|
|
14
|
+
this.copy = (vec3: Vector3) => {
|
|
15
|
+
this.x = vec3.x;
|
|
16
|
+
this.y = vec3.y;
|
|
17
|
+
this.z = vec3.z;
|
|
18
|
+
return this;
|
|
19
|
+
};
|
|
20
|
+
this.set = (x: number, y: number, z: number) => {
|
|
21
|
+
this.x = x;
|
|
22
|
+
this.y = y;
|
|
23
|
+
this.z = z;
|
|
24
|
+
return this;
|
|
25
|
+
};
|
|
26
|
+
this.multiply = (vec3: Vector3) => {
|
|
27
|
+
this.x *= vec3.x;
|
|
28
|
+
this.y *= vec3.y;
|
|
29
|
+
this.z *= vec3.z;
|
|
30
|
+
return this;
|
|
31
|
+
};
|
|
32
|
+
this.clone = () => {
|
|
33
|
+
return new Vector3(this.x, this.y, this.z);
|
|
34
|
+
};
|
|
35
|
+
this.setY = (y: number) => {
|
|
36
|
+
this.y = y;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
this.add = (vec3: Vector3) => {
|
|
40
|
+
this.x += vec3.x;
|
|
41
|
+
this.y += vec3.y;
|
|
42
|
+
this.z += vec3.z;
|
|
43
|
+
return this;
|
|
44
|
+
};
|
|
45
|
+
this.sub = (vec3: Vector3) => {
|
|
46
|
+
this.x -= vec3.x;
|
|
47
|
+
this.y -= vec3.y;
|
|
48
|
+
this.z -= vec3.z;
|
|
49
|
+
return this;
|
|
50
|
+
};
|
|
51
|
+
return this;
|
|
52
|
+
}),
|
|
53
|
+
Euler: jest.fn(function () {
|
|
54
|
+
this.set = jest.fn();
|
|
55
|
+
return this;
|
|
56
|
+
}),
|
|
57
|
+
Object3D: jest.fn(function () {
|
|
58
|
+
this.clear = jest.fn();
|
|
59
|
+
this.color = {};
|
|
60
|
+
this.intensity = 0;
|
|
61
|
+
this.layers = {
|
|
62
|
+
mask: 0,
|
|
63
|
+
};
|
|
64
|
+
this.shadow = {
|
|
65
|
+
radius: 0,
|
|
66
|
+
mapSize: { width: 0, height: 0 },
|
|
67
|
+
bias: 0,
|
|
68
|
+
camera: {
|
|
69
|
+
near: 0,
|
|
70
|
+
far: 0,
|
|
71
|
+
fov: 0,
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
this.add = jest.fn();
|
|
75
|
+
this.sub = jest.fn();
|
|
76
|
+
this.children = [{
|
|
77
|
+
visible: true,
|
|
78
|
+
material: {
|
|
79
|
+
color: {},
|
|
80
|
+
},
|
|
81
|
+
}];
|
|
82
|
+
this.userData = {};
|
|
83
|
+
this.position = new Vector3();
|
|
84
|
+
this.rotation = new Euler();
|
|
85
|
+
this.scale = new Vector3(1, 1, 1);
|
|
86
|
+
this.localToWorld = (vec3: Vector3) => {
|
|
87
|
+
return vec3;
|
|
88
|
+
};
|
|
89
|
+
this.mesh = new Mesh();
|
|
90
|
+
this.traverse = jest.fn((callback) => {
|
|
91
|
+
callback(this.children[0])
|
|
92
|
+
});
|
|
93
|
+
return this;
|
|
94
|
+
}),
|
|
95
|
+
Box3: jest.fn(function () {
|
|
96
|
+
this.min = new Vector3(Infinity, Infinity, Infinity);
|
|
97
|
+
this.max = new Vector3(-Infinity, -Infinity, -Infinity);
|
|
98
|
+
this.getCenter = jest.fn(() => {
|
|
99
|
+
return new Vector3(0, 0, 0);
|
|
100
|
+
});
|
|
101
|
+
this.expandByObject = jest.fn();
|
|
102
|
+
|
|
103
|
+
return this;
|
|
104
|
+
}),
|
|
105
|
+
Raycaster: jest.fn(function () {
|
|
106
|
+
this.intersectObjects = intersectObjectsMock;
|
|
107
|
+
this.layers = {
|
|
108
|
+
mask: 0,
|
|
109
|
+
};
|
|
110
|
+
return this;
|
|
111
|
+
}),
|
|
112
|
+
Mesh: jest.fn(function () {
|
|
113
|
+
this.geometry = {
|
|
114
|
+
computeBoundingBox: jest.fn(),
|
|
115
|
+
boundingBox: new Box3(),
|
|
116
|
+
};
|
|
117
|
+
this.material = {};
|
|
118
|
+
this.castShadow = true;
|
|
119
|
+
this.receiveShadow = true;
|
|
120
|
+
this.layers = {
|
|
121
|
+
mask: 0,
|
|
122
|
+
};
|
|
123
|
+
this.updateWorldMatrix = jest.fn();
|
|
124
|
+
this.traverse = jest.fn();
|
|
125
|
+
this.removeFromParent = jest.fn();
|
|
126
|
+
this.localToWorld = (vec3: Vector3) => {
|
|
127
|
+
return vec3;
|
|
128
|
+
};
|
|
129
|
+
return this;
|
|
130
|
+
}),
|
|
131
|
+
MeshStandardMaterial: jest.fn(function () {
|
|
132
|
+
this.color = new Color();
|
|
133
|
+
this.roughness = 1;
|
|
134
|
+
this.roughnessMap = undefined;
|
|
135
|
+
this.metalness = 0;
|
|
136
|
+
this.metalnessMap = undefined;
|
|
137
|
+
return this;
|
|
138
|
+
}),
|
|
139
|
+
Color: jest.fn(function () {
|
|
140
|
+
this.set = jest.fn();
|
|
141
|
+
return this;
|
|
142
|
+
}),
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
jest.mock('../../com/Communication.ts', () => {
|
|
147
|
+
return {
|
|
148
|
+
DIVECommunication: {
|
|
149
|
+
get: jest.fn(() => {
|
|
150
|
+
return {
|
|
151
|
+
PerformAction: jest.fn(),
|
|
152
|
+
}
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValue({ PerformAction: jest.fn() } as unknown as DIVECommunication);
|
|
159
|
+
|
|
160
|
+
let node: DIVENode;
|
|
161
|
+
|
|
162
|
+
describe('dive/node/DIVENode', () => {
|
|
163
|
+
beforeEach(() => {
|
|
164
|
+
node = new DIVENode();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
afterEach(() => {
|
|
168
|
+
jest.clearAllMocks();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should instantiate', () => {
|
|
172
|
+
expect(node).toBeDefined();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should set position', () => {
|
|
176
|
+
expect(() => node.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should set rotation', () => {
|
|
180
|
+
expect(() => node.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should set scale', () => {
|
|
184
|
+
expect(() => node.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should set visibility', () => {
|
|
188
|
+
expect(() => node.SetVisibility(true)).not.toThrow();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should set to world origin', () => {
|
|
192
|
+
node.userData.id = 'something';
|
|
193
|
+
|
|
194
|
+
expect(() => node.SetToWorldOrigin()).not.toThrow();
|
|
195
|
+
expect(node.position.x).toBe(0);
|
|
196
|
+
expect(node.position.y).toBe(0);
|
|
197
|
+
expect(node.position.z).toBe(0);
|
|
198
|
+
|
|
199
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
200
|
+
expect(() => node.SetToWorldOrigin()).not.toThrow();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should onMove', () => {
|
|
204
|
+
node.userData.id = 'something';
|
|
205
|
+
|
|
206
|
+
expect(() => node.onMove()).not.toThrow();
|
|
207
|
+
|
|
208
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
209
|
+
expect(() => node.onMove()).not.toThrow();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should onSelect', () => {
|
|
213
|
+
node.userData.id = 'something';
|
|
214
|
+
|
|
215
|
+
expect(() => node.onSelect()).not.toThrow();
|
|
216
|
+
|
|
217
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
218
|
+
expect(() => node.onSelect()).not.toThrow();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should onDeselect', () => {
|
|
222
|
+
node.userData.id = 'something';
|
|
223
|
+
|
|
224
|
+
expect(() => node.onDeselect()).not.toThrow();
|
|
225
|
+
|
|
226
|
+
jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
|
|
227
|
+
expect(() => node.onDeselect()).not.toThrow();
|
|
228
|
+
});
|
|
229
|
+
});
|