@shopware-ag/dive 1.16.8 → 1.16.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.16.8",
3
+ "version": "1.16.9",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "./build/dive.cjs",
@@ -1,4 +1,10 @@
1
- import { BufferGeometry, Line, LineDashedMaterial, Vector3 } from 'three';
1
+ import {
2
+ BufferGeometry,
3
+ Line,
4
+ LineDashedMaterial,
5
+ Vector3,
6
+ Vector3Like,
7
+ } from 'three';
2
8
  import { DIVENode } from '../node/Node';
3
9
  import { type Object3D } from 'three';
4
10
  import { type DIVESceneObject } from '../types';
@@ -20,6 +26,15 @@ export class DIVEGroup extends DIVENode {
20
26
  this._lines = [];
21
27
  }
22
28
 
29
+ public SetPosition(position: Vector3Like): void {
30
+ super.SetPosition(position);
31
+ this._members.forEach((member) => {
32
+ if ('isDIVENode' in member) {
33
+ (member as DIVENode).onMove();
34
+ }
35
+ });
36
+ }
37
+
23
38
  public SetLinesVisibility(visible: boolean, object?: Object3D): void {
24
39
  if (!object) {
25
40
  this._lines.forEach((line) => {
@@ -1,4 +1,6 @@
1
+ import { type Vector3Like } from 'three';
1
2
  import { DIVECommunication } from '../../com/Communication';
3
+ import { type DIVENode } from '../../node/Node';
2
4
  import { DIVEGroup } from '../Group';
3
5
 
4
6
  jest.mock('../../com/Communication.ts', () => {
@@ -107,4 +109,99 @@ describe('dive/group/DIVEGroup', () => {
107
109
  jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
108
110
  expect(() => group.onMove()).not.toThrow();
109
111
  });
112
+
113
+ it('should call onMove on members with isDIVENode', () => {
114
+ // Create mock members
115
+ const diveNode1: DIVENode = {
116
+ isDIVENode: true,
117
+ onMove: jest.fn(),
118
+ } as unknown as DIVENode;
119
+
120
+ const diveNode2: DIVENode = {
121
+ isDIVENode: true,
122
+ onMove: jest.fn(),
123
+ } as unknown as DIVENode;
124
+
125
+ const member1: DIVENode = {
126
+ // Define other properties/methods if necessary
127
+ } as unknown as DIVENode;
128
+
129
+ const member2: DIVENode = {
130
+ // Define other properties/methods if necessary
131
+ } as unknown as DIVENode;
132
+
133
+ // Assign the _members array (assuming it's protected or public for testing)
134
+ // If _members is private, you might need to use a different approach or modify the class for testability
135
+ (group as any)._members = [
136
+ diveNode1,
137
+ member1,
138
+ diveNode2,
139
+ member2,
140
+ ];
141
+
142
+ const position: Vector3Like = { x: 4, y: 5, z: 6 };
143
+ group.SetPosition(position);
144
+
145
+ // Check that onMove was called on diveNode1 and diveNode2
146
+ expect(diveNode1.onMove).toHaveBeenCalled();
147
+ expect(diveNode2.onMove).toHaveBeenCalled();
148
+
149
+ // Ensure onMove was not called on other members
150
+ // Since member1 and member2 don't have onMove, there's nothing to assert here
151
+ // If members have onMove, you should mock and verify they are not called
152
+ });
153
+
154
+ it('should not call onMove on members without isDIVENode', () => {
155
+ // Create mock members without isDIVENode
156
+ const member1: DIVENode = {
157
+ // Define other properties/methods if necessary
158
+ } as unknown as DIVENode;
159
+
160
+ const member2: DIVENode = {
161
+ // Define other properties/methods if necessary
162
+ } as unknown as DIVENode;
163
+
164
+ // Assign the _members array
165
+ (group as any)._members = [
166
+ member1,
167
+ member2,
168
+ ];
169
+
170
+ const position: Vector3Like = { x: 7, y: 8, z: 9 };
171
+ group.SetPosition(position);
172
+
173
+ // Since members do not have onMove, there's nothing to assert
174
+ // If members have onMove as optional, you can spy on them to ensure they're not called
175
+ });
176
+
177
+ it('should handle an empty _members array without errors', () => {
178
+ // Assign an empty _members array
179
+ (group as any)._members = [];
180
+
181
+ const position: Vector3Like = { x: 10, y: 11, z: 12 };
182
+ expect(() => group.SetPosition(position)).not.toThrow();
183
+ });
184
+
185
+ it('should handle _members with mixed types correctly', () => {
186
+ // Create mixed members
187
+ const diveNode: DIVENode = {
188
+ isDIVENode: true,
189
+ onMove: jest.fn(),
190
+ } as unknown as DIVENode;
191
+
192
+ const member: DIVENode = {
193
+ // Define other properties/methods if necessary
194
+ } as unknown as DIVENode;
195
+
196
+ (group as any)._members = [
197
+ diveNode,
198
+ member,
199
+ ];
200
+
201
+ const position: Vector3Like = { x: 13, y: 14, z: 15 };
202
+ group.SetPosition(position);
203
+
204
+ // Ensure onMove is called only on diveNode
205
+ expect(diveNode.onMove).toHaveBeenCalled();
206
+ });
110
207
  });
@@ -0,0 +1,179 @@
1
+ import degToRad from '../degToRad';
2
+ import { MathUtils } from 'three';
3
+
4
+ // Mock the 'three' module, specifically MathUtils.degToRad
5
+ jest.mock('three', () => ({
6
+ MathUtils: {
7
+ degToRad: jest.fn(),
8
+ },
9
+ }));
10
+
11
+ // Type assertion for the mocked MathUtils.degToRad
12
+ const mockedDegToRad = MathUtils.degToRad as jest.Mock;
13
+
14
+ /**
15
+ * Test Suite for degToRad Function
16
+ */
17
+ describe('degToRad', () => {
18
+ beforeEach(() => {
19
+ // Clear all previous mock calls and implementations before each test
20
+ mockedDegToRad.mockClear();
21
+ });
22
+
23
+ it('should convert 0 degrees to 0 radians', () => {
24
+ // Arrange
25
+ mockedDegToRad.mockReturnValue(0);
26
+
27
+ // Act
28
+ const result = degToRad(0);
29
+
30
+ // Assert
31
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(0);
32
+ expect(result).toBe(0);
33
+ });
34
+
35
+ it('should convert 180 degrees to π radians', () => {
36
+ // Arrange
37
+ const degrees = 180;
38
+ const radians = Math.PI;
39
+ mockedDegToRad.mockReturnValue(radians);
40
+
41
+ // Act
42
+ const result = degToRad(degrees);
43
+
44
+ // Assert
45
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
46
+ expect(result).toBe(radians);
47
+ });
48
+
49
+ it('should convert 360 degrees to 2π radians', () => {
50
+ // Arrange
51
+ const degrees = 360;
52
+ const radians = 2 * Math.PI;
53
+ mockedDegToRad.mockReturnValue(radians);
54
+
55
+ // Act
56
+ const result = degToRad(degrees);
57
+
58
+ // Assert
59
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
60
+ expect(result).toBe(radians);
61
+ });
62
+
63
+ it('should convert 90 degrees to π/2 radians', () => {
64
+ // Arrange
65
+ const degrees = 90;
66
+ const radians = Math.PI / 2;
67
+ mockedDegToRad.mockReturnValue(radians);
68
+
69
+ // Act
70
+ const result = degToRad(degrees);
71
+
72
+ // Assert
73
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
74
+ expect(result).toBe(radians);
75
+ });
76
+
77
+ it('should convert 45 degrees to π/4 radians', () => {
78
+ // Arrange
79
+ const degrees = 45;
80
+ const radians = Math.PI / 4;
81
+ mockedDegToRad.mockReturnValue(radians);
82
+
83
+ // Act
84
+ const result = degToRad(degrees);
85
+
86
+ // Assert
87
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
88
+ expect(result).toBe(radians);
89
+ });
90
+
91
+ it('should handle multiple calls with different degrees', () => {
92
+ // Arrange
93
+ const degrees1 = 30;
94
+ const radians1 = Math.PI / 6;
95
+ const degrees2 = 60;
96
+ const radians2 = Math.PI / 3;
97
+ const degrees3 = 120;
98
+ const radians3 = (2 * Math.PI) / 3;
99
+
100
+ mockedDegToRad
101
+ .mockReturnValueOnce(radians1)
102
+ .mockReturnValueOnce(radians2)
103
+ .mockReturnValueOnce(radians3);
104
+
105
+ // Act
106
+ const result1 = degToRad(degrees1);
107
+ const result2 = degToRad(degrees2);
108
+ const result3 = degToRad(degrees3);
109
+
110
+ // Assert
111
+ expect(MathUtils.degToRad).toHaveBeenNthCalledWith(1, degrees1);
112
+ expect(MathUtils.degToRad).toHaveBeenNthCalledWith(2, degrees2);
113
+ expect(MathUtils.degToRad).toHaveBeenNthCalledWith(3, degrees3);
114
+
115
+ expect(result1).toBe(radians1);
116
+ expect(result2).toBe(radians2);
117
+ expect(result3).toBe(radians3);
118
+ });
119
+
120
+ it('should handle edge case of degrees just below 360', () => {
121
+ // Arrange
122
+ const degrees = 359.999;
123
+ const radians = MathUtils.degToRad(degrees);
124
+ mockedDegToRad.mockReturnValue(radians);
125
+
126
+ // Act
127
+ const result = degToRad(degrees);
128
+
129
+ // Assert
130
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
131
+ expect(result).toBe(radians);
132
+ });
133
+
134
+ it('should not allow negative degrees', () => {
135
+ // Arrange
136
+ const degrees = -45;
137
+ const radians = MathUtils.degToRad(degrees);
138
+ mockedDegToRad.mockReturnValue(radians);
139
+
140
+ // Act
141
+ const result = degToRad(degrees);
142
+
143
+ // Assert
144
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
145
+ expect(result).toBe(radians);
146
+ // Depending on implementation, you might want to expect an error
147
+ // or handle negative degrees differently. Adjust assertions accordingly.
148
+ });
149
+
150
+ it('should handle undefined degrees gracefully', () => {
151
+ // Arrange
152
+ const degrees = undefined;
153
+ // Since the function expects a number, this might throw an error or pass undefined
154
+ mockedDegToRad.mockReturnValue(NaN);
155
+
156
+ // Act
157
+ // @ts-ignore: Testing undefined input
158
+ const result = degToRad(degrees);
159
+
160
+ // Assert
161
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
162
+ expect(result).toBe(NaN);
163
+ });
164
+
165
+ it('should handle null degrees gracefully', () => {
166
+ // Arrange
167
+ const degrees = null;
168
+ // Depending on implementation, this might throw an error or pass null
169
+ mockedDegToRad.mockReturnValue(NaN);
170
+
171
+ // Act
172
+ // @ts-ignore: Testing null input
173
+ const result = degToRad(degrees);
174
+
175
+ // Assert
176
+ expect(MathUtils.degToRad).toHaveBeenCalledWith(degrees);
177
+ expect(result).toBe(NaN);
178
+ });
179
+ });
@@ -0,0 +1,5 @@
1
+ import { MathUtils } from 'three';
2
+
3
+ export default function degToRad(degrees: number): number {
4
+ return MathUtils.degToRad(degrees);
5
+ }
package/src/math/index.ts CHANGED
@@ -4,6 +4,8 @@ import roundExp from './round/roundExp.ts';
4
4
  import signedAngleTo from './signedAngleTo/signedAngleTo.ts';
5
5
  import toFixedExp from './toFixed/toFixedExp.ts';
6
6
  import truncateExp from './truncate/truncateExp.ts';
7
+ import radToDeg from './radToDeg/radToDeg.ts';
8
+ import degToRad from './degToRad/degToRad.ts';
7
9
 
8
10
  export const DIVEMath: {
9
11
  ceilExp: typeof ceilExp;
@@ -12,6 +14,8 @@ export const DIVEMath: {
12
14
  toFixedExp: typeof toFixedExp;
13
15
  truncateExp: typeof truncateExp;
14
16
  signedAngleTo: typeof signedAngleTo;
17
+ radToDeg: typeof radToDeg;
18
+ degToRad: typeof degToRad;
15
19
  } = {
16
20
  ceilExp,
17
21
  floorExp,
@@ -19,4 +23,6 @@ export const DIVEMath: {
19
23
  toFixedExp,
20
24
  truncateExp,
21
25
  signedAngleTo,
26
+ radToDeg,
27
+ degToRad,
22
28
  };
@@ -0,0 +1,162 @@
1
+ import radToDeg from '../radToDeg';
2
+ import { MathUtils } from 'three';
3
+
4
+ // Mock the 'three' module, specifically MathUtils.radToDeg
5
+ jest.mock('three', () => ({
6
+ MathUtils: {
7
+ radToDeg: jest.fn(),
8
+ },
9
+ }));
10
+
11
+ // Type assertion for the mocked MathUtils.radToDeg
12
+ const mockedRadToDeg = MathUtils.radToDeg as jest.Mock;
13
+
14
+ /**
15
+ * Test Suite for radToDeg Function
16
+ */
17
+ describe('radToDeg', () => {
18
+ beforeEach(() => {
19
+ // Clear all previous mock calls and implementations before each test
20
+ mockedRadToDeg.mockClear();
21
+ });
22
+
23
+ it('should convert 0 radians to 0 degrees', () => {
24
+ // Arrange
25
+ mockedRadToDeg.mockReturnValue(0);
26
+
27
+ // Act
28
+ const result = radToDeg(0);
29
+
30
+ // Assert
31
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(0);
32
+ expect(result).toBe(0);
33
+ });
34
+
35
+ it('should convert π radians to 180 degrees', () => {
36
+ // Arrange
37
+ const pi = Math.PI;
38
+ mockedRadToDeg.mockReturnValue(180);
39
+
40
+ // Act
41
+ const result = radToDeg(pi);
42
+
43
+ // Assert
44
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(pi);
45
+ expect(result).toBe(180);
46
+ });
47
+
48
+ it('should convert 2π radians to 0 degrees (wrapped)', () => {
49
+ // Arrange
50
+ const twoPi = 2 * Math.PI;
51
+ mockedRadToDeg.mockReturnValue(360);
52
+
53
+ // Act
54
+ const result = radToDeg(twoPi);
55
+
56
+ // Assert
57
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(twoPi);
58
+ expect(result).toBe(0);
59
+ });
60
+
61
+ it('should convert 3π/2 radians to 270 degrees', () => {
62
+ // Arrange
63
+ const threePiOver2 = (3 * Math.PI) / 2;
64
+ mockedRadToDeg.mockReturnValue(270);
65
+
66
+ // Act
67
+ const result = radToDeg(threePiOver2);
68
+
69
+ // Assert
70
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(threePiOver2);
71
+ expect(result).toBe(270);
72
+ });
73
+
74
+ it('should handle angles greater than 2π radians correctly', () => {
75
+ // Arrange
76
+ const sevenPi = 7 * Math.PI; // 1260 degrees
77
+ const expectedDegrees = (1260 + 360) % 360; // 180 degrees
78
+ mockedRadToDeg.mockReturnValue(1260);
79
+
80
+ // Act
81
+ const result = radToDeg(sevenPi);
82
+
83
+ // Assert
84
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(sevenPi);
85
+ expect(result).toBe(expectedDegrees);
86
+ });
87
+
88
+ it('should handle fractional radians correctly', () => {
89
+ // Arrange
90
+ const fractionalRadians = Math.PI / 4; // 45 degrees
91
+ mockedRadToDeg.mockReturnValue(45);
92
+
93
+ // Act
94
+ const result = radToDeg(fractionalRadians);
95
+
96
+ // Assert
97
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(fractionalRadians);
98
+ expect(result).toBe(45);
99
+ });
100
+
101
+ it('should wrap negative angles correctly', () => {
102
+ // Since the function does not handle negative inputs, this test ensures it behaves as expected
103
+ // However, based on initial requirements, negative degrees are not allowed and inputs are non-negative
104
+ // This test is optional and based on how you want the function to behave
105
+ const negativeRadians = -Math.PI / 2; // -90 degrees
106
+ mockedRadToDeg.mockReturnValue(-90);
107
+ const expectedDegrees = (-90 + 360) % 360; // 270 degrees
108
+
109
+ const result = radToDeg(negativeRadians);
110
+
111
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(negativeRadians);
112
+ expect(result).toBe(expectedDegrees);
113
+ });
114
+
115
+ it('should handle multiple full rotations correctly', () => {
116
+ // Arrange
117
+ const multipleRotations = 5 * 2 * Math.PI; // 360 * 5 = 1800 degrees
118
+ const expectedDegrees = (1800 + 360) % 360; // 0 degrees
119
+ mockedRadToDeg.mockReturnValue(1800);
120
+
121
+ // Act
122
+ const result = radToDeg(multipleRotations);
123
+
124
+ // Assert
125
+ expect(MathUtils.radToDeg).toHaveBeenCalledWith(multipleRotations);
126
+ expect(result).toBe(0);
127
+ });
128
+
129
+ it('should handle mixed angles', () => {
130
+ // Arrange
131
+ const angles = [
132
+ Math.PI / 6,
133
+ Math.PI,
134
+ (5 * Math.PI) / 3,
135
+ ];
136
+ const mockReturns = [
137
+ 30,
138
+ 180,
139
+ 300,
140
+ ];
141
+ const expectedDegrees = [
142
+ (30 + 360) % 360,
143
+ (180 + 360) % 360,
144
+ (300 + 360) % 360,
145
+ ]; // [30, 180, 300]
146
+
147
+ mockedRadToDeg
148
+ .mockReturnValueOnce(mockReturns[0])
149
+ .mockReturnValueOnce(mockReturns[1])
150
+ .mockReturnValueOnce(mockReturns[2]);
151
+
152
+ // Act & Assert for each angle
153
+ angles.forEach((angle, index) => {
154
+ const result = radToDeg(angle);
155
+ expect(MathUtils.radToDeg).toHaveBeenNthCalledWith(
156
+ index + 1,
157
+ angle,
158
+ );
159
+ expect(result).toBe(expectedDegrees[index]);
160
+ });
161
+ });
162
+ });
@@ -0,0 +1,5 @@
1
+ import { MathUtils } from 'three';
2
+
3
+ export default function radToDeg(radians: number): number {
4
+ return (MathUtils.radToDeg(radians) + 360) % 360;
5
+ }
package/src/node/Node.ts CHANGED
@@ -67,6 +67,9 @@ export class DIVENode extends Object3D implements DIVESelectable, DIVEMovable {
67
67
  );
68
68
  }
69
69
 
70
+ /**
71
+ * Can be called when the object is moved from a foreign object (gizmo, parent, etc.) to update the object's position.
72
+ */
70
73
  public onMove(): void {
71
74
  DIVECommunication.get(this.userData.id)?.PerformAction(
72
75
  'UPDATE_OBJECT',