@wemap/geo 1.0.5 → 2.7.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.
@@ -1,63 +1,89 @@
1
1
  import {
2
- Rotations, Utils as MathUtils, Quaternion
2
+ Rotations, Quaternion, rad2deg, deg2rad
3
3
  } from '@wemap/maths';
4
4
 
5
- const rotxM90 = Quaternion.fromAxisAngle([1, 0, 0], -Math.PI / 2);
6
-
7
5
  class Attitude {
8
6
 
9
- quaternion = [1, 0, 0, 0];
10
- quaternionThreeJsV = null;
11
- headingV = null;
12
- headingDegreesV = null;
13
- eulerAnglesV = null;
14
- eulerAnglesDegreesV = null;
7
+ _quaternion = [1, 0, 0, 0];
8
+ _heading = null;
9
+ _eulerAngles = null;
15
10
 
16
11
  constructor(quaternion) {
17
12
  this.quaternion = quaternion;
18
13
  }
19
14
 
15
+ static unitary() {
16
+ return new Attitude([1, 0, 0, 0]);
17
+ }
18
+
19
+ get quaternion() {
20
+ return this._quaternion;
21
+ }
22
+
23
+ set quaternion(quaternion) {
24
+ if (!Array.isArray(quaternion)
25
+ || quaternion.length !== 4
26
+ || Math.abs(1 - Quaternion.norm(quaternion)) > 1e-4) {
27
+ throw new Error('quaternion is not a unit quaternion');
28
+ }
29
+ this._quaternion = quaternion;
30
+ }
31
+
20
32
  get eulerAngles() {
21
- if (!this.eulerAnglesV) {
22
- this.eulerAnglesV = Rotations.quaternionToEulerZXY(this.quaternion);
33
+ if (this._eulerAngles === null) {
34
+ this._eulerAngles = Rotations.quaternionToEulerZXY(this.quaternion);
23
35
  }
24
- return this.eulerAnglesV;
36
+ return this._eulerAngles;
25
37
  }
26
38
 
27
39
  get eulerAnglesDegrees() {
28
- if (!this.eulerAnglesDegreesV) {
29
- this.eulerAnglesDegreesV = Rotations.quaternionToEulerZXYDegrees(this.quaternion);
30
- }
31
- return this.eulerAnglesDegreesV;
40
+ return this.eulerAngles.map(x => rad2deg(x));
32
41
  }
33
42
 
34
43
  get heading() {
35
- if (!this.headingV) {
36
- this.headingV = Rotations.getHeadingFromQuaternion(this.quaternion) + MathUtils.deg2rad(window.orientation || 0);
44
+ if (this._heading === null) {
45
+ let offset = 0;
46
+ if (global.window && global.window.orientation) {
47
+ offset = deg2rad(global.window.orientation);
48
+ }
49
+ this._heading = Rotations.getHeadingFromQuaternion(this.quaternion) + offset;
37
50
  }
38
- return this.headingV;
51
+ return this._heading;
39
52
  }
40
53
 
41
54
  get headingDegrees() {
42
- if (!this.headingDegreesV) {
43
- this.headingDegreesV = MathUtils.rad2deg(Rotations.getHeadingFromQuaternion(this.quaternion)) + (window.orientation || 0);
44
- }
45
- return this.headingDegreesV;
55
+ return rad2deg(this.heading);
46
56
  }
47
57
 
48
- get quaternionThreeJs() {
49
- if (!this.quaternionThreeJsV) {
50
- this.quaternionThreeJsV = Quaternion.wxyz2xyzw(Quaternion.multiply(rotxM90, this.quaternion));
58
+ /**
59
+ * Compares two Attitude
60
+ * @param {Attitude} att1 attitude 1
61
+ * @param {Attitude} att2 attitude 2
62
+ */
63
+ static equalsTo(att1, att2) {
64
+
65
+ // Handle null comparison
66
+ if (att1 === null && att1 === att2) {
67
+ return true;
68
+ }
69
+
70
+ if (!(att1 instanceof Attitude) || !(att2 instanceof Attitude)) {
71
+ return false;
51
72
  }
52
- return this.quaternionThreeJsV;
73
+
74
+ return Quaternion.distance(att1.quaternion, att2.quaternion) < 1e-8;
75
+ }
76
+
77
+ equalsTo(other) {
78
+ return Attitude.equalsTo(this, other);
53
79
  }
54
80
 
55
- toMessage() {
81
+ toJson() {
56
82
  return this.quaternion;
57
83
  }
58
84
 
59
- static fromMessage(message) {
60
- return new Attitude(message);
85
+ static fromJson(json) {
86
+ return new Attitude(json);
61
87
  }
62
88
 
63
89
  }
@@ -0,0 +1,82 @@
1
+ import chai from 'chai';
2
+ import chaiAlmost from 'chai-almost';
3
+
4
+ import Attitude from './Attitude';
5
+
6
+ const expect = chai.expect;
7
+ chai.use(chaiAlmost());
8
+
9
+ describe('Attitude', () => {
10
+
11
+ it('creation', () => {
12
+ expect(() => new Attitude()).throw(Error);
13
+ expect(() => new Attitude(true)).throw(Error);
14
+ expect(() => new Attitude(false)).throw(Error);
15
+ expect(() => new Attitude([])).throw(Error);
16
+ expect(() => new Attitude([1])).throw(Error);
17
+ expect(() => new Attitude([1, 2, 3, 4])).throw(Error);
18
+ expect(() => new Attitude([1, 1, 1, 1])).throw(Error);
19
+ expect(() => new Attitude([0, 0, 0, 1])).not.throw(Error);
20
+ expect(() => new Attitude([0.5, 0.5, 0.5, 0.5])).not.throw(Error);
21
+ expect(() => new Attitude([Math.sqrt(2) / 2, Math.sqrt(2) / 2, 0, 0])).not.throw(Error);
22
+ expect(Attitude.unitary().quaternion).deep.equals([1, 0, 0, 0]);
23
+ });
24
+
25
+ it('eulerAngles', () => {
26
+
27
+ const attitude = new Attitude([1, 0, 0, 0]);
28
+ expect(attitude.eulerAngles).deep.equals([0, 0, 0]);
29
+ expect(attitude.eulerAngles).deep.equals([0, 0, 0]);
30
+
31
+ expect(new Attitude([0, 1, 0, 0]).eulerAngles).deep.equals([Math.PI, 0, Math.PI]);
32
+ expect(new Attitude([0, 0, 1, 0]).eulerAngles).deep.equals([0, 0, Math.PI]);
33
+ expect(new Attitude([0, 0, 0, 1]).eulerAngles).deep.equals([Math.PI, 0, 0]);
34
+
35
+ expect(new Attitude([1, 0, 0, 0]).eulerAnglesDegrees).deep.equals([0, 0, 0]);
36
+ expect(new Attitude([0, 0, 1, 0]).eulerAnglesDegrees).deep.equals([0, 0, 180]);
37
+ });
38
+
39
+ it('heading', () => {
40
+ const attitude = new Attitude([1, 0, 0, 0]);
41
+ expect(attitude.heading).equals(0);
42
+ expect(attitude.heading).equals(0);
43
+
44
+ expect(new Attitude([Math.sqrt(2) / 2, Math.sqrt(2) / 2, 0, 0]).heading).equals(0);
45
+ expect(new Attitude([-0.5, 0.5, 0.5, 0.5]).heading).equals(Math.PI / 2);
46
+
47
+ const tmpWindow = global.window;
48
+ global.window = { orientation: 90 };
49
+ expect(new Attitude([1, 0, 0, 0]).heading).equals(Math.PI / 2);
50
+ expect(new Attitude([Math.sqrt(2) / 2, Math.sqrt(2) / 2, 0, 0]).heading).equals(Math.PI / 2);
51
+ expect(new Attitude([-0.5, 0.5, 0.5, 0.5]).heading).equals(Math.PI);
52
+ global.window = tmpWindow;
53
+
54
+ expect(new Attitude([-0.5, 0.5, 0.5, 0.5]).headingDegrees).equals(90);
55
+ });
56
+
57
+ it('equalsTo', () => {
58
+
59
+ expect(Attitude.equalsTo(null, null)).true;
60
+ expect(Attitude.equalsTo(new Attitude([-0.5, 0.5, 0.5, 0.5]), new Attitude([1, 0, 0, 0]))).false;
61
+ expect(Attitude.equalsTo([-0.5, 0.5, 0.5, 0.5], new Attitude([1, 0, 0, 0]))).false;
62
+ expect(Attitude.equalsTo(new Attitude([1, 0, 0, 0]), [-0.5, 0.5, 0.5, 0.5])).false;
63
+ expect(new Attitude([1, 0, 0, 0]).equalsTo(new Attitude([1, 0, 0, 0]))).true;
64
+ expect(new Attitude([-0.5, 0.5, 0.5, 0.5]).equalsTo(new Attitude([-0.5, 0.5, 0.5, 0.5]))).true;
65
+
66
+ });
67
+
68
+
69
+ it('json', () => {
70
+
71
+ let attitude;
72
+
73
+ attitude = new Attitude([1, 0, 0, 0]);
74
+ expect(attitude.toJson()).deep.equals([1, 0, 0, 0]);
75
+ expect(attitude.equalsTo(Attitude.fromJson(attitude.toJson()))).true;
76
+
77
+ attitude = new Attitude([-0.5, 0.5, 0.5, 0.5]);
78
+ expect(attitude.toJson()).deep.equals([-0.5, 0.5, 0.5, 0.5]);
79
+ expect(attitude.equalsTo(Attitude.fromJson(attitude.toJson()))).true;
80
+ });
81
+
82
+ });