@wemap/geo 10.0.0-alpha.0 → 10.0.0-alpha.10

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/index.d.ts CHANGED
@@ -16,9 +16,6 @@ declare module '@wemap/geo' {
16
16
  static toString(level: Level_t): string;
17
17
  static equals(first: Level_t, second: Level_t): boolean;
18
18
  static diff(first: Level_t, second: Level_t): null | number;
19
-
20
- /** @deprecated */
21
- static fromLegacy(level: (null | { isRange: boolean, val?: number, low?: number, up?: number })): Level_t;
22
19
  }
23
20
 
24
21
  type CoordinatesCompressedJson = [number, number] |
@@ -65,22 +62,6 @@ declare module '@wemap/geo' {
65
62
  toCompressedJson(): CoordinatesCompressedJson;
66
63
  static fromJson(json: CoordinatesJson): Coordinates;
67
64
  static fromCompressedJson(json: CoordinatesCompressedJson): Coordinates;
68
-
69
- /** @deprecated */
70
- toLegacyJson(): any;
71
- /** @deprecated */
72
- toLegacyCompressedJson():
73
- [number, number] |
74
- [number, number, number] |
75
- [number, number, number, string] |
76
- [number, number, null, string];
77
- /** @deprecated */
78
- static fromLegacyCompressedJson(json:
79
- [number, number] |
80
- [number, number, number] |
81
- [number, number, number, string] |
82
- [number, number, null, string]): Coordinates;
83
-
84
65
  }
85
66
 
86
67
  export type AttitudeJson = Quaternion_t
@@ -104,6 +85,7 @@ declare module '@wemap/geo' {
104
85
  static unitary(): Attitude;
105
86
  static equals(attitude1: Attitude, attitude2: Attitude): boolean;
106
87
  static fromJson(json: AttitudeJson): Attitude;
88
+ static diff(attitudeStart: Attitude, attitudeEnd: Attitude): Attitude;
107
89
  }
108
90
 
109
91
  export class GeoRef {
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "directory": "packages/geo"
14
14
  },
15
15
  "name": "@wemap/geo",
16
- "version": "10.0.0-alpha.0",
16
+ "version": "10.0.0-alpha.10",
17
17
  "bugs": {
18
18
  "url": "https://github.com/wemap/wemap-modules-js/issues"
19
19
  },
@@ -28,8 +28,8 @@
28
28
  ],
29
29
  "license": "ISC",
30
30
  "dependencies": {
31
- "@wemap/logger": "^9.0.0",
32
- "@wemap/maths": "^9.0.0"
31
+ "@wemap/logger": "^10.0.0-alpha.8",
32
+ "@wemap/maths": "^10.0.0-alpha.10"
33
33
  },
34
- "gitHead": "d98a62dea33f5bcd93bc0eda133242da9fe441e3"
34
+ "gitHead": "5970289ef2b1f06f9df382878f72bf48f57c4c00"
35
35
  }
@@ -1,5 +1,3 @@
1
- import Logger from '@wemap/logger';
2
-
3
1
  import {
4
2
  deg2rad, Vector3, Quaternion, rad2deg, wrap
5
3
  } from '@wemap/maths';
@@ -448,32 +446,11 @@ class Coordinates {
448
446
  return output;
449
447
  }
450
448
 
451
- /**
452
- * @returns {!Object}
453
- */
454
- toLegacyJson() {
455
- const output = {
456
- lat: this.lat,
457
- lng: this.lng
458
- };
459
- if (this.alt !== null) {
460
- output.alt = this.alt;
461
- }
462
- if (this.level !== null) {
463
- output.level = Level.toString(this.level);
464
- }
465
- return output;
466
- }
467
-
468
449
  /**
469
450
  * @param {!Object} json
470
451
  * @returns {!Coordinates}
471
452
  */
472
453
  static fromJson(json) {
473
- if (typeof json.level === 'string') {
474
- Logger.warn('Still using legacy level format. Please update your project.');
475
- return new Coordinates(json.lat, json.lng, json.alt, Level.fromString(json.level));
476
- }
477
454
  return new Coordinates(json.lat, json.lng, json.alt, json.level);
478
455
  }
479
456
 
@@ -491,21 +468,6 @@ class Coordinates {
491
468
  return output;
492
469
  }
493
470
 
494
- /**
495
- * @returns {!Object}
496
- * @deprecated
497
- */
498
- toLegacyCompressedJson() {
499
- const output = [this.lat, this.lng];
500
- if (this.alt !== null || this.level !== null) {
501
- output.push(this.alt);
502
- }
503
- if (this.level !== null) {
504
- output.push(Level.toString(this.level));
505
- }
506
- return output;
507
- }
508
-
509
471
  /**
510
472
  * @param {!Object} json
511
473
  * @returns {!Coordinates}
@@ -516,27 +478,7 @@ class Coordinates {
516
478
  coords.alt = json[2];
517
479
  }
518
480
  if (json.length > 3) {
519
- if (typeof json[3] === 'string') {
520
- Logger.warn('Still using legacy level format. Please update your project.');
521
- coords.level = Level.fromString(json[3]);
522
- } else {
523
- coords.level = json[3];
524
- }
525
- }
526
- return coords;
527
- }
528
-
529
- /**
530
- * @param {!Object} json
531
- * @returns {!Coordinates}
532
- */
533
- static fromLegacyCompressedJson(json) {
534
- const coords = new Coordinates(json[0], json[1]);
535
- if (json.length > 2) {
536
- coords.alt = json[2];
537
- }
538
- if (json.length > 3) {
539
- coords.level = Level.fromString(json[3]);
481
+ coords.level = json[3];
540
482
  }
541
483
  return coords;
542
484
  }
@@ -250,12 +250,6 @@ describe('Coordinates', () => {
250
250
  level: [1, 2]
251
251
  });
252
252
 
253
- expect(new Coordinates(5, -10, null, [1, 2]).toLegacyJson()).to.deep.equal({
254
- lat: 5,
255
- lng: -10,
256
- level: '1;2'
257
- });
258
-
259
253
  expect(new Coordinates(5, -10, 3, [1, 2]).toJson()).to.deep.equal({
260
254
  lat: 5,
261
255
  lng: -10,
@@ -263,13 +257,6 @@ describe('Coordinates', () => {
263
257
  level: [1, 2]
264
258
  });
265
259
 
266
- expect(new Coordinates(5, -10, 3, [1, 2]).toLegacyJson()).to.deep.equal({
267
- lat: 5,
268
- lng: -10,
269
- alt: 3,
270
- level: '1;2'
271
- });
272
-
273
260
  let position;
274
261
 
275
262
  position = new Coordinates(0, 0);
@@ -296,20 +283,10 @@ describe('Coordinates', () => {
296
283
  ).true;
297
284
 
298
285
  expect(Coordinates.equals(
299
- Coordinates.fromCompressedJson([5, -10, null, '1']),
300
- new Coordinates(5, -10, null, 1))
301
- ).true;
302
-
303
- expect(Coordinates.equals(
304
- Coordinates.fromCompressedJson([5, -10, null, '1;2']),
286
+ Coordinates.fromCompressedJson([5, -10, null, [1, 2]]),
305
287
  new Coordinates(5, -10, null, [1, 2]))
306
288
  ).true;
307
289
 
308
- expect(Coordinates.equals(
309
- Coordinates.fromCompressedJson([5, -10, 10, '2;3']),
310
- new Coordinates(5, -10, 10, [2, 3]))
311
- ).true;
312
-
313
290
  });
314
291
 
315
292
  });
@@ -23,7 +23,7 @@ class GeoRef {
23
23
  const rotationOffset = Quaternion.fromAxisAngle([0, 0, 1], this.heading);
24
24
  const enuToEcefRotationOrigin = Quaternion.multiply(rotationOffset, this.origin.enuToEcefRotation);
25
25
  const ecefTranslation = Quaternion.rotate(enuToEcefRotationOrigin, enuTranslationScaled);
26
- const ecef = Vector3.add(this.origin.ecef, ecefTranslation);
26
+ const ecef = Vector3.sum(this.origin.ecef, ecefTranslation);
27
27
  return Coordinates.fromECEF(ecef);
28
28
  }
29
29
 
@@ -331,20 +331,6 @@ class Level {
331
331
 
332
332
  return null;
333
333
  }
334
-
335
- /**
336
- * @param {null|{isRange: boolean, val?: number, low?: number, up?: number}} legacyLevel
337
- * @deprecated
338
- */
339
- static fromLegacy(legacyLevel) {
340
- if (legacyLevel === null) {
341
- return null;
342
- }
343
- if (legacyLevel.isRange) {
344
- return [legacyLevel.low, legacyLevel.up];
345
- }
346
- return legacyLevel.val;
347
- }
348
334
  }
349
335
 
350
336
  export default Level;
@@ -225,15 +225,4 @@ describe('Level', () => {
225
225
  expect(Level.diff([0, 1], [0, 1])).equals(0);
226
226
  expect(Level.diff([0, 1], [0, 2])).is.null;
227
227
  });
228
-
229
-
230
- it('fromLegacy', () => {
231
- expect(Level.fromLegacy(null)).is.null;
232
- expect(Level.fromLegacy({ isRange: false, val: 0 })).equals(0);
233
- expect(Level.fromLegacy({ isRange: false, val: 6 })).equals(6);
234
- expect(Level.fromLegacy({ isRange: false, val: -5 })).equals(-5);
235
- expect(Level.fromLegacy({ isRange: true, low: 0, up: 1 })).deep.equals([0, 1]);
236
- expect(Level.fromLegacy({ isRange: true, low: -5, up: 5 })).deep.equals([-5, 5]);
237
- });
238
-
239
228
  });
@@ -1,5 +1,3 @@
1
- import Logger from '@wemap/logger';
2
-
3
1
  import Coordinates from '../coordinates/Coordinates.js';
4
2
  import Level from '../coordinates/Level.js';
5
3
 
@@ -107,14 +105,12 @@ class GraphNode {
107
105
  } else {
108
106
  tmpLevel = Level.intersection(tmpLevel, edge.level);
109
107
  if (tmpLevel === null) {
110
- Logger.error('Error: Something bad happend during parsing: We cannot retrieve node level from adjacent ways: ' + this.coords);
111
- return false;
108
+ throw Error('Something bad happend during parsing: We cannot retrieve node level from adjacent ways: ' + this.coords);
112
109
  }
113
110
  }
114
111
  }
115
112
  }
116
113
  this.coords.level = tmpLevel;
117
- return true;
118
114
  }
119
115
 
120
116
 
@@ -124,14 +120,14 @@ class GraphNode {
124
120
  _inferNodeLevelByRecursion() {
125
121
  const { level } = this.coords;
126
122
  if (level === null || !Level.isRange(level)) {
127
- return true;
123
+ return;
128
124
  }
129
125
 
130
126
  /**
131
127
  * We can infer node level only if this one have one edge attached
132
128
  */
133
129
  if (this.edges.length > 1) {
134
- return true;
130
+ return;
135
131
  }
136
132
 
137
133
  /**
@@ -169,13 +165,10 @@ class GraphNode {
169
165
  if (othersLevels !== null) {
170
166
  if (!Level.isRange(othersLevels)) {
171
167
  this.coords.level = othersLevels === level[0] ? level[1] : level[0];
172
- return true;
168
+ return;
173
169
  }
174
- Logger.warn('Level of: ' + this.coords.toString() + ' cannot be decided');
175
- return false;
170
+ throw Error('Level of: ' + this.coords.toString() + ' cannot be decided');
176
171
  }
177
-
178
- return true;
179
172
  }
180
173
 
181
174
  /**
@@ -215,23 +208,17 @@ class GraphNode {
215
208
  * @param {GraphNode[]} nodes
216
209
  */
217
210
  static generateNodesLevels(nodes) {
218
- const success = nodes.reduce((acc, node) => acc && node._generateLevelFromEdges(), true);
219
- if (!success) {
220
- return false;
221
- }
211
+
212
+ nodes.forEach(node => node._generateLevelFromEdges());
222
213
 
223
214
  // In some cases, node levels cannot be retrieve just using adjacent edges
224
215
  // (e.g stairs without network at one of its bounds)
225
216
  // To infer this node level, we use inferNodeLevelByRecursion()
226
- const res = nodes.reduce((acc, node) => acc
227
- && node._inferNodeLevelByNeighboors()
228
- && node._inferNodeLevelByRecursion()
229
- , true);
217
+ nodes.forEach(node => node._inferNodeLevelByNeighboors());
218
+ nodes.forEach(node => node._inferNodeLevelByRecursion());
230
219
 
231
220
  // Finally define nodes that are links between indoor and outdoor
232
221
  nodes.forEach(node => node._checkIO());
233
-
234
- return res;
235
222
  }
236
223
  }
237
224
 
@@ -86,23 +86,23 @@ describe('GraphNode', () => {
86
86
  */
87
87
 
88
88
  nodes = cleanNodesWithAdjEdges(1, 0);
89
- expect(GraphNode.generateNodesLevels(nodes)).false;
89
+ expect(() => GraphNode.generateNodesLevels(nodes)).throw(Error);
90
90
  expect(nodes[0].coords.level).is.null;
91
91
 
92
92
  nodes = cleanNodesWithAdjEdges(1, 1);
93
- expect(GraphNode.generateNodesLevels(nodes)).true;
93
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
94
94
  expect(Level.equals(nodes[0].coords.level, 1)).true;
95
95
 
96
96
  nodes = cleanNodesWithAdjEdges(1, [1, 2]);
97
- expect(GraphNode.generateNodesLevels(nodes)).true;
97
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
98
98
  expect(Level.equals(nodes[0].coords.level, 1)).true;
99
99
 
100
100
  nodes = cleanNodesWithAdjEdges([0, 1], [1, 2]);
101
- expect(GraphNode.generateNodesLevels(nodes)).true;
101
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
102
102
  expect(Level.equals(nodes[0].coords.level, 1)).true;
103
103
 
104
104
  nodes = cleanNodesWithAdjEdges([0, 1]);
105
- expect(GraphNode.generateNodesLevels(nodes)).true;
105
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
106
106
  expect(Level.equals(nodes[0].coords.level, [0, 1])).true;
107
107
 
108
108
  /**
@@ -113,7 +113,7 @@ describe('GraphNode', () => {
113
113
  new GraphEdge(nodes[0], nodes[1], 1, 'e0');
114
114
  new GraphEdge(nodes[1], nodes[2], [1, 2], 'e1');
115
115
  new GraphEdge(nodes[2], nodes[3], [1, 2], 'e2');
116
- expect(GraphNode.generateNodesLevels(nodes)).true;
116
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
117
117
  expect(Level.equals(nodes[0].coords.level, 1)).true;
118
118
  expect(Level.equals(nodes[1].coords.level, 1)).true;
119
119
  expect(Level.equals(nodes[2].coords.level, [1, 2])).true;
@@ -125,14 +125,14 @@ describe('GraphNode', () => {
125
125
  new GraphEdge(nodes[1], nodes[2], [1, 2], 'e1');
126
126
  new GraphEdge(nodes[2], nodes[3], [1, 2], 'e2');
127
127
  new GraphEdge(nodes[2], nodes[4], null, 'e3');
128
- expect(GraphNode.generateNodesLevels(nodes)).true;
128
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
129
129
 
130
130
 
131
131
  nodes = cleanNodes(4);
132
132
  new GraphEdge(nodes[0], nodes[1], 1, 'e0');
133
133
  new GraphEdge(nodes[1], nodes[2], [0, 1], 'e1');
134
134
  new GraphEdge(nodes[2], nodes[3], [0, 1], 'e2');
135
- expect(GraphNode.generateNodesLevels(nodes)).true;
135
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
136
136
  expect(Level.equals(nodes[0].coords.level, 1)).true;
137
137
  expect(Level.equals(nodes[1].coords.level, 1)).true;
138
138
  expect(Level.equals(nodes[2].coords.level, [0, 1])).true;
@@ -144,7 +144,7 @@ describe('GraphNode', () => {
144
144
  new GraphEdge(nodes[1], nodes[2], [1, 2], 'e1');
145
145
  new GraphEdge(nodes[2], nodes[3], [1, 2], 'e2');
146
146
  new GraphEdge(nodes[1], nodes[3], 1, 'e3');
147
- expect(GraphNode.generateNodesLevels(nodes)).true;
147
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
148
148
  expect(Level.equals(nodes[0].coords.level, 1)).true;
149
149
  expect(Level.equals(nodes[1].coords.level, 1)).true;
150
150
  expect(Level.equals(nodes[2].coords.level, 2)).true;
@@ -156,7 +156,7 @@ describe('GraphNode', () => {
156
156
  new GraphEdge(nodes[1], nodes[2], [0, 1], 'e1');
157
157
  new GraphEdge(nodes[2], nodes[3], [0, 1], 'e2');
158
158
  new GraphEdge(nodes[1], nodes[3], 1, 'e3');
159
- expect(GraphNode.generateNodesLevels(nodes)).true;
159
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
160
160
  expect(Level.equals(nodes[0].coords.level, 1)).true;
161
161
  expect(Level.equals(nodes[1].coords.level, 1)).true;
162
162
  expect(Level.equals(nodes[2].coords.level, 0)).true;
@@ -169,7 +169,7 @@ describe('GraphNode', () => {
169
169
  new GraphEdge(nodes[2], nodes[3], [1, 2], 'e2');
170
170
  new GraphEdge(nodes[2], nodes[4], [1, 2], 'e3');
171
171
  new GraphEdge(nodes[4], nodes[5], 2, 'e4');
172
- expect(GraphNode.generateNodesLevels(nodes)).false;
172
+ expect(() => GraphNode.generateNodesLevels(nodes)).throw(Error);
173
173
 
174
174
 
175
175
  nodes = cleanNodes(5);
@@ -177,7 +177,7 @@ describe('GraphNode', () => {
177
177
  new GraphEdge(nodes[1], nodes[2], [1, 2]);
178
178
  new GraphEdge(nodes[2], nodes[3], [1, 2]);
179
179
  new GraphEdge(nodes[3], nodes[4], 1);
180
- expect(GraphNode.generateNodesLevels(nodes)).true;
180
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
181
181
  expect(Level.equals(nodes[0].coords.level, 2)).true;
182
182
  expect(Level.equals(nodes[1].coords.level, [1, 2])).true;
183
183
  expect(Level.equals(nodes[2].coords.level, [1, 2])).true;
@@ -191,7 +191,7 @@ describe('GraphNode', () => {
191
191
  new GraphEdge(nodes[2], nodes[3], [0, 1], 'e2');
192
192
  new GraphEdge(nodes[3], nodes[4], [0, 1], 'e3');
193
193
  new GraphEdge(nodes[4], nodes[5], 1, 'e4');
194
- expect(GraphNode.generateNodesLevels(nodes)).true;
194
+ expect(() => GraphNode.generateNodesLevels(nodes)).not.throw(Error);
195
195
  expect(Level.equals(nodes[1].coords.level, 0)).true;
196
196
  expect(Level.equals(nodes[1].coords.level, 0)).true;
197
197
  expect(Level.equals(nodes[2].coords.level, [0, 1])).true;
@@ -161,8 +161,15 @@ class Network {
161
161
 
162
162
  const network = new Network();
163
163
 
164
- const getOrCreateNode = coords =>
165
- network.nodes.find(_coords => _coords.equals(coords)) || new GraphNode(coords);
164
+ const getOrCreateNode = coords => {
165
+ const node = network.nodes.find(otherNode => otherNode.coords.equals(coords));
166
+ if (node) {
167
+ return node;
168
+ }
169
+ const newNode = new GraphNode(coords);
170
+ network.nodes.push(newNode);
171
+ return newNode;
172
+ };
166
173
 
167
174
 
168
175
  const createEdgeFromNodes = (node1, node2) =>
@@ -179,7 +186,6 @@ class Network {
179
186
  network.edges.push(edge);
180
187
  }
181
188
 
182
- network.nodes.push(currentNode);
183
189
  previousNode = currentNode;
184
190
  }
185
191
  }
@@ -187,6 +187,30 @@ class Attitude {
187
187
  clone() {
188
188
  return new Attitude(this.quaternion.slice(0), this.time, this.accuracy);
189
189
  }
190
+
191
+ /**
192
+ * Calculate the relative attitude between two given attitudes
193
+ * @param {Attitude} attitudeStart
194
+ * @param {Attitude} attitudeEnd
195
+ * @returns {Attitude}
196
+ */
197
+ static diff(attitudeStart, attitudeEnd) {
198
+
199
+ const quaternionDiff = Quaternion.multiply(
200
+ Quaternion.inverse(attitudeStart.quaternion),
201
+ attitudeEnd.quaternion
202
+ );
203
+
204
+ const timeDiff = attitudeEnd.time - attitudeStart.time;
205
+
206
+ let accuracyDiff = null;
207
+ if (attitudeStart.accuracy !== null && attitudeEnd.accuracy !== null) {
208
+ // Approximation
209
+ accuracyDiff = Math.max(attitudeEnd.accuracy - attitudeStart.accuracy);
210
+ }
211
+
212
+ return new Attitude(quaternionDiff, timeDiff, accuracyDiff);
213
+ }
190
214
  }
191
215
 
192
216
  export default Attitude;
@@ -230,19 +230,19 @@ describe('Attitude', () => {
230
230
  expect(attitude.equals(Attitude.fromJson(attitude.toJson()))).true;
231
231
 
232
232
  attitude = new Attitude([1, 0, 0, 0], 2);
233
- expect(attitude.toJson()).deep.equals({q: [1, 0, 0, 0], time: 2});
233
+ expect(attitude.toJson()).deep.equals({ q: [1, 0, 0, 0], time: 2 });
234
234
  attitudeBis = Attitude.fromJson(attitude.toJson());
235
235
  expect(attitude.equals(attitudeBis)).true;
236
236
  expect(attitudeBis.time).equals(2);
237
237
 
238
238
  attitude = new Attitude([1, 0, 0, 0], null, 3);
239
- expect(attitude.toJson()).deep.equals({q: [1, 0, 0, 0], accuracy: 3});
239
+ expect(attitude.toJson()).deep.equals({ q: [1, 0, 0, 0], accuracy: 3 });
240
240
  attitudeBis = Attitude.fromJson(attitude.toJson());
241
241
  expect(attitude.equals(attitudeBis)).true;
242
242
  expect(attitudeBis.accuracy).equals(3);
243
243
 
244
244
  attitude = new Attitude([1, 0, 0, 0], 2, 3);
245
- expect(attitude.toJson()).deep.equals({q: [1, 0, 0, 0], time: 2, accuracy: 3});
245
+ expect(attitude.toJson()).deep.equals({ q: [1, 0, 0, 0], time: 2, accuracy: 3 });
246
246
  attitudeBis = Attitude.fromJson(attitude.toJson());
247
247
  expect(attitude.equals(attitudeBis)).true;
248
248
  expect(attitudeBis.time).equals(2);
@@ -250,4 +250,34 @@ describe('Attitude', () => {
250
250
 
251
251
  });
252
252
 
253
+ it('diff', () => {
254
+
255
+ let startAttitude, endAttitude, diffAttitude;
256
+
257
+ startAttitude = new Attitude(LAYED_PORTRAIT_NORTH, 0, 0);
258
+ endAttitude = new Attitude(LAYED_PORTRAIT_EAST, 2, Math.PI / 4);
259
+ diffAttitude = Attitude.diff(startAttitude, endAttitude);
260
+ checkAngles(diffAttitude.heading, Math.PI / 2);
261
+ expect(Quaternion.equals(diffAttitude.quaternion, Quaternion.fromAxisAngle([0, 0, 1], -Math.PI / 2))).true;
262
+ expect(diffAttitude.time).equals(2);
263
+ expect(diffAttitude.accuracy).equals(Math.PI / 4);
264
+
265
+ endAttitude = new Attitude(LAYED_PORTRAIT_SOUTH);
266
+ diffAttitude = Attitude.diff(startAttitude, endAttitude);
267
+ checkAngles(diffAttitude.heading, Math.PI);
268
+ expect(Quaternion.equals(diffAttitude.quaternion, Quaternion.fromAxisAngle([0, 0, 1], Math.PI))).true;
269
+
270
+ endAttitude = new Attitude(STAND_PORTRAIT_NORTH);
271
+ diffAttitude = Attitude.diff(startAttitude, endAttitude);
272
+ checkAngles(diffAttitude.heading, 0);
273
+ expect(Quaternion.equals(diffAttitude.quaternion, Quaternion.fromAxisAngle([1, 0, 0], Math.PI / 2))).true;
274
+
275
+ startAttitude = new Attitude(STAND_PORTRAIT_SOUTH);
276
+ endAttitude = new Attitude(STAND_PORTRAIT_EAST);
277
+ diffAttitude = Attitude.diff(startAttitude, endAttitude);
278
+ checkAngles(diffAttitude.heading, -Math.PI / 2);
279
+ expect(Quaternion.equals(diffAttitude.quaternion, Quaternion.fromAxisAngle([0, 1, 0], Math.PI / 2))).true;
280
+
281
+ });
282
+
253
283
  });