@navaramap/three-api 0.0.8 → 0.1.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.
- package/LICENSE +1 -1
- package/README.md +30 -1
- package/dist/ellipsoidGeodesic.d.ts +12 -10
- package/dist/index.d.ts +3 -4
- package/dist/index.js +66 -66
- package/dist/index.umd.cjs +1 -1
- package/package.json +3 -3
- package/src/ellipsoidGeodesic.ts +32 -20
- package/src/index.test.ts +2 -0
- package/src/index.ts +17 -10
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
1
|
# @navaramap/three-api
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Standalone geodetic and GIS math for Three.js, powered by Navara's WASM core. It covers geodetic ⇔ ECEF conversion, WGS84 ellipsoid constants and surface normals, local tangent frames (ENU/NED/NUE/NWU/WUN and heading/pitch/roll placement), screen ⇔ world projection and pick rays, ray/plane intersection, ellipsoid geodesics, and RTE (relative-to-eye) encoding for jitter-free rendering far from the origin. Everything is integrated with the Three.js type system (`Vector3`, `Matrix4`, cameras).
|
|
4
|
+
|
|
5
|
+
Unlike the rest of the Navara stack, this package is usable without the map engine: it is the standalone form of Navara's API tier, for pure geometry computation in any Three.js app.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
Initialize the WASM module once before calling anything else (when using `@navaramap/three`, `view.init()` does this for you):
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { initNavaraApi, geodeticToVector3 } from "@navaramap/three-api";
|
|
13
|
+
|
|
14
|
+
await initNavaraApi();
|
|
15
|
+
|
|
16
|
+
// Geodetic coordinates (degrees, meters) to ECEF Cartesian.
|
|
17
|
+
const position = geodeticToVector3({
|
|
18
|
+
lng: 139.77,
|
|
19
|
+
lat: 35.68,
|
|
20
|
+
height: 0,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
All of these utilities are also re-exported by `@navaramap/three`, so applications using the map engine don't need a direct dependency on this package.
|
|
25
|
+
|
|
26
|
+
## Documentation
|
|
27
|
+
|
|
28
|
+
Every function is documented at https://navara.world/docs/.
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
MIT OR Apache-2.0
|
|
@@ -3,11 +3,13 @@ import { LatLngHeight } from '@navaramap/core';
|
|
|
3
3
|
* Wrapper class for geodesic calculations on an ellipsoid surface.
|
|
4
4
|
* Precomputes common variables for optimization when instantiated.
|
|
5
5
|
*
|
|
6
|
+
* All latitudes/longitudes and headings are in **degrees**.
|
|
7
|
+
*
|
|
6
8
|
* @example
|
|
7
9
|
* ```typescript
|
|
8
10
|
* const geodesic = new EllipsoidGeodesic(
|
|
9
|
-
* { lat:
|
|
10
|
-
* { lat:
|
|
11
|
+
* { lat: 35.6812, lng: 139.7671, height: 0 },
|
|
12
|
+
* { lat: 34.7025, lng: 135.4959, height: 0 }
|
|
11
13
|
* );
|
|
12
14
|
*
|
|
13
15
|
* console.log(geodesic.distance);
|
|
@@ -21,8 +23,8 @@ export declare class EllipsoidGeodesic {
|
|
|
21
23
|
private _raw;
|
|
22
24
|
/**
|
|
23
25
|
* Create a new geodesic between two points on the ellipsoid.
|
|
24
|
-
* @param start - Start point in geodetic coordinates (lat/lng in
|
|
25
|
-
* @param end - End point in geodetic coordinates (lat/lng in
|
|
26
|
+
* @param start - Start point in geodetic coordinates (lat/lng in degrees)
|
|
27
|
+
* @param end - End point in geodetic coordinates (lat/lng in degrees)
|
|
26
28
|
*/
|
|
27
29
|
constructor(start: LatLngHeight, end: LatLngHeight);
|
|
28
30
|
/** Distance in meters between start and end points */
|
|
@@ -34,24 +36,24 @@ export declare class EllipsoidGeodesic {
|
|
|
34
36
|
* unreliable solution.
|
|
35
37
|
*/
|
|
36
38
|
get converged(): boolean;
|
|
37
|
-
/** Heading at the start point in
|
|
39
|
+
/** Heading at the start point in degrees */
|
|
38
40
|
get startHeading(): number;
|
|
39
|
-
/** Heading at the end point in
|
|
41
|
+
/** Heading at the end point in degrees */
|
|
40
42
|
get endHeading(): number;
|
|
41
|
-
/** Start point in geodetic coordinates */
|
|
43
|
+
/** Start point in geodetic coordinates (lat/lng in degrees) */
|
|
42
44
|
get start(): LatLngHeight;
|
|
43
|
-
/** End point in geodetic coordinates */
|
|
45
|
+
/** End point in geodetic coordinates (lat/lng in degrees) */
|
|
44
46
|
get end(): LatLngHeight;
|
|
45
47
|
/**
|
|
46
48
|
* Interpolate points along the geodesic path.
|
|
47
49
|
* @param granularity - Distance between interpolated points in meters (optional)
|
|
48
|
-
* @returns Array of interpolated points in geodetic coordinates
|
|
50
|
+
* @returns Array of interpolated points in geodetic coordinates (lat/lng in degrees)
|
|
49
51
|
*/
|
|
50
52
|
interpolatePoints(granularity?: number): LatLngHeight[];
|
|
51
53
|
/**
|
|
52
54
|
* Interpolate a point at a specific distance along the geodesic path.
|
|
53
55
|
* @param distance - Distance from start point in meters
|
|
54
|
-
* @returns Interpolated point in geodetic coordinates
|
|
56
|
+
* @returns Interpolated point in geodetic coordinates (lat/lng in degrees)
|
|
55
57
|
*/
|
|
56
58
|
interpolateDistance(distance: number): LatLngHeight;
|
|
57
59
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -13,14 +13,14 @@ export * from './ellipsoidGeodesic';
|
|
|
13
13
|
export declare function initNavaraApi(): Promise<void>;
|
|
14
14
|
/**
|
|
15
15
|
* Converts geodetic coordinates (longitude, latitude, height) to a Cartesian Vector3 in ECEF coordinates.
|
|
16
|
-
* @param lle - Geodetic coordinates (lng in
|
|
16
|
+
* @param lle - Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
17
17
|
* @returns Cartesian Vector3 in Earth-Centered Earth-Fixed (ECEF) coordinates
|
|
18
18
|
*/
|
|
19
19
|
export declare function geodeticToVector3(lle: LatLngHeight): Vector3;
|
|
20
20
|
/**
|
|
21
21
|
* Converts a Cartesian Vector3 in ECEF coordinates to geodetic coordinates.
|
|
22
22
|
* @param xyz - Cartesian Vector3 in Earth-Centered Earth-Fixed (ECEF) coordinates
|
|
23
|
-
* @returns Geodetic coordinates (lng in
|
|
23
|
+
* @returns Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
24
24
|
*/
|
|
25
25
|
export declare function vector3ToGeodetic(xyz: Vector3): LatLngHeight;
|
|
26
26
|
/**
|
|
@@ -45,7 +45,7 @@ export declare function radianToDegree(radian: number): number;
|
|
|
45
45
|
export declare function convertScreenToWorld(windowObject: WindowObject, camera: PerspectiveCamera, vec2: Vector2): Vector3 | undefined;
|
|
46
46
|
/**
|
|
47
47
|
* Computes the surface normal vector at a geodetic position on the WGS84 ellipsoid.
|
|
48
|
-
* @param lle - Geodetic coordinates (lng in
|
|
48
|
+
* @param lle - Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
49
49
|
* @returns Unit normal vector pointing outward from the ellipsoid surface
|
|
50
50
|
*/
|
|
51
51
|
export declare function geodeticSurfaceNormal(lle: LatLngHeight): Vector3;
|
|
@@ -97,7 +97,6 @@ export declare function westUpNorthToFixedFrame(origin: Vector3): Matrix4;
|
|
|
97
97
|
* engines differ in which axis they treat as an asset's front, so a model
|
|
98
98
|
* ported from one may need a multiple of 90° added to its heading.
|
|
99
99
|
*
|
|
100
|
-
* NOTE: unlike {@link geodeticToVector3} and the other helpers in this module,
|
|
101
100
|
* `lng`/`lat` and all angles here are in **degrees**, matching
|
|
102
101
|
* `setCamera` and the `geodetic` mesh Descriptor field.
|
|
103
102
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import e, { CameraFrustum as t, EllipsoidGeodesic as n, LLE as r, Ray as i, Transform as a, Vec2 as o, Vec3 as s, Window as c, angleToDegree as l, angleToRadian as u, eastNorthUpToFixedFrame as d, encodePosition as f, geodeticSurfaceNormal as p, geodeticToXyz as m, getHeightFromEllipsoid as h, getPickRay as g, getPlaneFromPointNormal as _, getRayPlaneIntersection as v, getWGS84Eccentricity as y, getWGS84EccentricitySquared as b, getWGS84Flattening as x, getWGS84SemiMajorAxis as
|
|
2
|
-
import { Euler as
|
|
1
|
+
import e, { CameraFrustum as t, EllipsoidGeodesic as n, LLE as r, Ray as i, Transform as a, Vec2 as o, Vec3 as s, Window as c, angleToDegree as l, angleToRadian as u, eastNorthUpToFixedFrame as d, encodePosition as f, geodeticSurfaceNormal as p, geodeticToXyz as m, getHeightFromEllipsoid as h, getPickRay as g, getPlaneFromPointNormal as _, getRayPlaneIntersection as v, getWGS84Eccentricity as y, getWGS84EccentricitySquared as b, getWGS84Flattening as x, getWGS84SemiMajorAxis as S, getWGS84SemiMinorAxis as C, northEastDownToFixedFrame as ee, northUpEastToFixedFrame as te, northWestUpToFixedFrame as w, screenToWorld as T, worldToScreen as E, xyzToGeodetic as D } from "@navaramap/engine-api";
|
|
2
|
+
import { Euler as O, MathUtils as k, Matrix4 as A, Plane as j, Ray as M, Vector2 as N, Vector3 as P } from "three";
|
|
3
3
|
//#region src/frames.ts
|
|
4
|
-
function
|
|
5
|
-
return new
|
|
4
|
+
function F() {
|
|
5
|
+
return new A().makeRotationY(Math.PI / 2);
|
|
6
6
|
}
|
|
7
|
-
function
|
|
8
|
-
let n = new
|
|
7
|
+
function I(e, t) {
|
|
8
|
+
let n = new A().multiplyMatrices(e, new A().makeRotationFromEuler(new O(-k.degToRad(t.pitch ?? 0), -k.degToRad(t.heading ?? 0), k.degToRad(t.roll ?? 0), "YXZ")));
|
|
9
9
|
if (t.scale !== void 0) {
|
|
10
10
|
let e = t.scale;
|
|
11
|
-
n.scale(typeof e == "number" ? new
|
|
11
|
+
n.scale(typeof e == "number" ? new P(e, e, e) : new P(e.x, e.y, e.z));
|
|
12
12
|
}
|
|
13
13
|
return n;
|
|
14
14
|
}
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/intersection.ts
|
|
17
|
-
function
|
|
18
|
-
let n = new s(e.x, e.y, e.z), r = new s(t.x, t.y, t.z), i = _(n, r), a = new
|
|
17
|
+
function L(e, t) {
|
|
18
|
+
let n = new s(e.x, e.y, e.z), r = new s(t.x, t.y, t.z), i = _(n, r), a = new P(i.normal.x, i.normal.y, i.normal.z), o = new j(a, -i.distance);
|
|
19
19
|
return i.free(), o;
|
|
20
20
|
}
|
|
21
|
-
function
|
|
21
|
+
function R(e, n, r) {
|
|
22
22
|
let i = new c(e.width, e.height, e.pixelRatio);
|
|
23
23
|
i.width *= i.pixelRatio, i.height *= i.pixelRatio;
|
|
24
|
-
let s = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d = g(i, s, l, new o(r.x, r.y)), f = new
|
|
24
|
+
let s = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d = g(i, s, l, new o(r.x, r.y)), f = new P(d.origin.x, d.origin.y, d.origin.z), p = new P(d.direction.x, d.direction.y, d.direction.z), m = new M(f, p);
|
|
25
25
|
return d.free(), m;
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function z(e, t) {
|
|
28
28
|
let n = new i(new s(e.origin.x, e.origin.y, e.origin.z), new s(e.direction.x, e.direction.y, e.direction.z)), r = _(new s(t.normal.x * -t.constant, t.normal.y * -t.constant, t.normal.z * -t.constant), new s(t.normal.x, t.normal.y, t.normal.z)), a = v(n, r);
|
|
29
29
|
if (a) {
|
|
30
|
-
let e = new
|
|
30
|
+
let e = new P(a.x, a.y, a.z);
|
|
31
31
|
return a.free(), e;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function B(e) {
|
|
35
35
|
let t = new s(e.x, e.y, e.z);
|
|
36
36
|
return h(t);
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/rte.ts
|
|
40
|
-
var
|
|
41
|
-
function
|
|
40
|
+
var V = Object.freeze({ value: 1 });
|
|
41
|
+
function H(e, t = new P(), n = new P()) {
|
|
42
42
|
let r = f(e.x, e.y, e.z);
|
|
43
43
|
return t.set(r.high.x, r.high.y, r.high.z), n.set(r.low.x, r.low.y, r.low.z), r.free(), {
|
|
44
44
|
high: t,
|
|
45
45
|
low: n
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
var
|
|
48
|
+
var ne = (e, t, n = new A()) => {
|
|
49
49
|
n.multiplyMatrices(t, e);
|
|
50
50
|
let r = n.elements;
|
|
51
51
|
return r[12] = 0, r[13] = 0, r[14] = 0, n;
|
|
52
52
|
};
|
|
53
|
-
function
|
|
53
|
+
function U(e, t, n = new P(), r = new A()) {
|
|
54
54
|
r.multiplyMatrices(e, t), n.setFromMatrixPosition(r);
|
|
55
55
|
let i = r.elements;
|
|
56
56
|
return i[12] = 0, i[13] = 0, i[14] = 0, {
|
|
@@ -58,17 +58,17 @@ function H(e, t, n = new N(), r = new k()) {
|
|
|
58
58
|
rotationScale: r
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
let n = f(
|
|
64
|
-
high: new
|
|
65
|
-
low: new
|
|
61
|
+
var W = new A(), G = new P(), K = (e, t) => {
|
|
62
|
+
W.copy(t).invert(), G.copy(e).applyMatrix4(W);
|
|
63
|
+
let n = f(G.x, G.y, G.z), r = n.high, i = n.low, a = {
|
|
64
|
+
high: new P(r.x, r.y, r.z),
|
|
65
|
+
low: new P(i.x, i.y, i.z)
|
|
66
66
|
};
|
|
67
67
|
return n.free(), a;
|
|
68
|
-
},
|
|
68
|
+
}, q = class {
|
|
69
69
|
_raw;
|
|
70
70
|
constructor(e, t) {
|
|
71
|
-
this._raw = new n(new r(e.lat, e.lng, e.height), new r(t.lat, t.lng, t.height));
|
|
71
|
+
this._raw = new n(new r(u(e.lat), u(e.lng), e.height), new r(u(t.lat), u(t.lng), t.height));
|
|
72
72
|
}
|
|
73
73
|
get distance() {
|
|
74
74
|
return this._raw.distance;
|
|
@@ -77,40 +77,40 @@ var U = new k(), W = new N(), G = (e, t) => {
|
|
|
77
77
|
return this._raw.converged;
|
|
78
78
|
}
|
|
79
79
|
get startHeading() {
|
|
80
|
-
return this._raw.start_heading;
|
|
80
|
+
return l(this._raw.start_heading);
|
|
81
81
|
}
|
|
82
82
|
get endHeading() {
|
|
83
|
-
return this._raw.end_heading;
|
|
83
|
+
return l(this._raw.end_heading);
|
|
84
84
|
}
|
|
85
85
|
get start() {
|
|
86
86
|
let e = this._raw.start;
|
|
87
87
|
return {
|
|
88
|
-
lat: e.lat,
|
|
89
|
-
lng: e.lng,
|
|
88
|
+
lat: l(e.lat),
|
|
89
|
+
lng: l(e.lng),
|
|
90
90
|
height: e.height
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
get end() {
|
|
94
94
|
let e = this._raw.end;
|
|
95
95
|
return {
|
|
96
|
-
lat: e.lat,
|
|
97
|
-
lng: e.lng,
|
|
96
|
+
lat: l(e.lat),
|
|
97
|
+
lng: l(e.lng),
|
|
98
98
|
height: e.height
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
interpolatePoints(e) {
|
|
102
102
|
let t = this._raw.interpolateGeodeticPoints(e ?? null), n = [];
|
|
103
103
|
for (let e of t) n.push({
|
|
104
|
-
lat: e.lat,
|
|
105
|
-
lng: e.lng,
|
|
104
|
+
lat: l(e.lat),
|
|
105
|
+
lng: l(e.lng),
|
|
106
106
|
height: e.height
|
|
107
107
|
}), e.free();
|
|
108
108
|
return n;
|
|
109
109
|
}
|
|
110
110
|
interpolateDistance(e) {
|
|
111
111
|
let t = this._raw.interpolateDistance(e), n = {
|
|
112
|
-
lat: t.lat,
|
|
113
|
-
lng: t.lng,
|
|
112
|
+
lat: l(t.lat),
|
|
113
|
+
lng: l(t.lng),
|
|
114
114
|
height: t.height
|
|
115
115
|
};
|
|
116
116
|
return t.free(), n;
|
|
@@ -121,78 +121,78 @@ var U = new k(), W = new N(), G = (e, t) => {
|
|
|
121
121
|
};
|
|
122
122
|
//#endregion
|
|
123
123
|
//#region src/index.ts
|
|
124
|
-
async function
|
|
124
|
+
async function J() {
|
|
125
125
|
await e();
|
|
126
126
|
}
|
|
127
|
-
function
|
|
128
|
-
let t = m(new r(e.lat, e.lng, e.height)), n = new
|
|
127
|
+
function Y(e) {
|
|
128
|
+
let t = m(new r(u(e.lat), u(e.lng), e.height)), n = new P(t.x, t.y, t.z);
|
|
129
129
|
return t.free(), n;
|
|
130
130
|
}
|
|
131
|
-
function
|
|
132
|
-
let t = new s(e.x, e.y, e.z), n =
|
|
133
|
-
lat: n.lat,
|
|
134
|
-
lng: n.lng,
|
|
131
|
+
function X(e) {
|
|
132
|
+
let t = new s(e.x, e.y, e.z), n = D(t), r = {
|
|
133
|
+
lat: l(n.lat),
|
|
134
|
+
lng: l(n.lng),
|
|
135
135
|
height: n.height
|
|
136
136
|
};
|
|
137
137
|
return n.free(), r;
|
|
138
138
|
}
|
|
139
|
-
function
|
|
139
|
+
function Z(e) {
|
|
140
140
|
return u(e);
|
|
141
141
|
}
|
|
142
|
-
function
|
|
142
|
+
function re(e) {
|
|
143
143
|
return l(e);
|
|
144
144
|
}
|
|
145
|
-
function
|
|
145
|
+
function ie(e, n, r) {
|
|
146
146
|
let i = new c(e.width, e.height, e.pixelRatio);
|
|
147
147
|
i.width *= i.pixelRatio, i.height *= i.pixelRatio;
|
|
148
|
-
let s = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d =
|
|
148
|
+
let s = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d = T(i, s, l, new o(r.x, r.y));
|
|
149
149
|
if (!d) return;
|
|
150
|
-
let f = new
|
|
150
|
+
let f = new P(d.x, d.y, d.z);
|
|
151
151
|
return d.free(), f;
|
|
152
152
|
}
|
|
153
|
-
function
|
|
154
|
-
let t = p(new r(e.lat, e.lng, e.height)), n = new
|
|
153
|
+
function ae(e) {
|
|
154
|
+
let t = p(new r(u(e.lat), u(e.lng), e.height)), n = new P(t.x, t.y, t.z);
|
|
155
155
|
return t.free(), n;
|
|
156
156
|
}
|
|
157
|
-
function
|
|
157
|
+
function oe(e) {
|
|
158
158
|
let t = new s(e.x, e.y, e.z), n = d(t);
|
|
159
|
-
return new
|
|
159
|
+
return new A().fromArray(n);
|
|
160
160
|
}
|
|
161
161
|
function se(e) {
|
|
162
|
-
let t = new s(e.x, e.y, e.z), n =
|
|
163
|
-
return new
|
|
162
|
+
let t = new s(e.x, e.y, e.z), n = ee(t);
|
|
163
|
+
return new A().fromArray(n);
|
|
164
164
|
}
|
|
165
165
|
function Q(e) {
|
|
166
|
-
let t = new s(e.x, e.y, e.z), n =
|
|
167
|
-
return new
|
|
166
|
+
let t = new s(e.x, e.y, e.z), n = te(t);
|
|
167
|
+
return new A().fromArray(n);
|
|
168
168
|
}
|
|
169
169
|
function ce(e) {
|
|
170
|
-
let t = new s(e.x, e.y, e.z), n =
|
|
171
|
-
return new
|
|
170
|
+
let t = new s(e.x, e.y, e.z), n = w(t);
|
|
171
|
+
return new A().fromArray(n);
|
|
172
172
|
}
|
|
173
173
|
function $(e) {
|
|
174
|
-
return Q(e).multiply(
|
|
174
|
+
return Q(e).multiply(F());
|
|
175
175
|
}
|
|
176
176
|
function le(e) {
|
|
177
|
-
return
|
|
178
|
-
lng:
|
|
179
|
-
lat:
|
|
177
|
+
return I($(Y({
|
|
178
|
+
lng: e.lng,
|
|
179
|
+
lat: e.lat,
|
|
180
180
|
height: e.height ?? 0
|
|
181
181
|
})), e);
|
|
182
182
|
}
|
|
183
183
|
function ue(e, n, r) {
|
|
184
184
|
let i = new c(e.width, e.height, e.pixelRatio);
|
|
185
185
|
i.width *= i.pixelRatio, i.height *= i.pixelRatio;
|
|
186
|
-
let o = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d =
|
|
186
|
+
let o = new a(n.position.x, n.position.y, n.position.z, n.quaternion.x, n.quaternion.y, n.quaternion.z, n.quaternion.w, n.scale.x, n.scale.y, n.scale.z), l = new t(n.near, n.far, u(n.fov), n.aspect), d = E(i, o, l, new s(r.x, r.y, r.z));
|
|
187
187
|
if (!d) return;
|
|
188
|
-
let f = new
|
|
188
|
+
let f = new N(d.x, d.y);
|
|
189
189
|
return d.free(), f;
|
|
190
190
|
}
|
|
191
191
|
function de() {
|
|
192
|
-
return
|
|
192
|
+
return S();
|
|
193
193
|
}
|
|
194
194
|
function fe() {
|
|
195
|
-
return
|
|
195
|
+
return C();
|
|
196
196
|
}
|
|
197
197
|
function pe() {
|
|
198
198
|
return b();
|
|
@@ -204,4 +204,4 @@ function he() {
|
|
|
204
204
|
return y();
|
|
205
205
|
}
|
|
206
206
|
//#endregion
|
|
207
|
-
export {
|
|
207
|
+
export { q as EllipsoidGeodesic, V as RTE_ONE_UNIFORM, K as calcCameraPosition, ne as calcModelMatrixRTE, U as composeWorldMatrixForRTE, ie as convertScreenToWorld, ue as convertWorldToScreen, Z as degreeToRadian, oe as eastNorthUpToFixedFrame, H as encodePositionRTE, ae as geodeticSurfaceNormal, Y as geodeticToVector3, B as getHeightFromEllipsoid, R as getPickRay, L as getPlaneFromPointNormal, z as getRayPlaneIntersection, he as getWGS84Eccentricity, pe as getWGS84EccentricitySquared, me as getWGS84Flattening, de as getWGS84SemiMajorAxis, fe as getWGS84SemiMinorAxis, le as headingPitchRollToFixedFrame, J as initNavaraApi, se as northEastDownToFixedFrame, Q as northUpEastToFixedFrame, ce as northWestUpToFixedFrame, re as radianToDegree, X as vector3ToGeodetic, $ as westUpNorthToFixedFrame };
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@navaramap/engine-api"),require("three")):typeof define==`function`&&define.amd?define([`exports`,`@navaramap/engine-api`,`three`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.NavaraThreeApi={},e._navaramap_engine_api,e.three))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:r(s(e)),l(t||!e||!e.__esModule||!c.call(e,`default`)?i(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function u(){return new n.Matrix4().makeRotationY(Math.PI/2)}function d(e,t){let r=new n.Matrix4().multiplyMatrices(e,new n.Matrix4().makeRotationFromEuler(new n.Euler(-n.MathUtils.degToRad(t.pitch??0),-n.MathUtils.degToRad(t.heading??0),n.MathUtils.degToRad(t.roll??0),`YXZ`)));if(t.scale!==void 0){let e=t.scale;r.scale(typeof e==`number`?new n.Vector3(e,e,e):new n.Vector3(e.x,e.y,e.z))}return r}function f(e,r){let i=new t.Vec3(e.x,e.y,e.z),a=new t.Vec3(r.x,r.y,r.z),o=(0,t.getPlaneFromPointNormal)(i,a),s=new n.Vector3(o.normal.x,o.normal.y,o.normal.z),c=new n.Plane(s,-o.distance);return o.free(),c}function p(e,r,i){let a=new t.Window(e.width,e.height,e.pixelRatio);a.width*=a.pixelRatio,a.height*=a.pixelRatio;let o=new t.Transform(r.position.x,r.position.y,r.position.z,r.quaternion.x,r.quaternion.y,r.quaternion.z,r.quaternion.w,r.scale.x,r.scale.y,r.scale.z),s=new t.CameraFrustum(r.near,r.far,(0,t.angleToRadian)(r.fov),r.aspect),c=(0,t.getPickRay)(a,o,s,new t.Vec2(i.x,i.y)),l=new n.Vector3(c.origin.x,c.origin.y,c.origin.z),u=new n.Vector3(c.direction.x,c.direction.y,c.direction.z),d=new n.Ray(l,u);return c.free(),d}function m(e,r){let i=new t.Ray(new t.Vec3(e.origin.x,e.origin.y,e.origin.z),new t.Vec3(e.direction.x,e.direction.y,e.direction.z)),a=(0,t.getPlaneFromPointNormal)(new t.Vec3(r.normal.x*-r.constant,r.normal.y*-r.constant,r.normal.z*-r.constant),new t.Vec3(r.normal.x,r.normal.y,r.normal.z)),o=(0,t.getRayPlaneIntersection)(i,a);if(o){let e=new n.Vector3(o.x,o.y,o.z);return o.free(),e}}function h(e){let n=new t.Vec3(e.x,e.y,e.z);return(0,t.getHeightFromEllipsoid)(n)}var g=Object.freeze({value:1});function _(e,r=new n.Vector3,i=new n.Vector3){let a=(0,t.encodePosition)(e.x,e.y,e.z);return r.set(a.high.x,a.high.y,a.high.z),i.set(a.low.x,a.low.y,a.low.z),a.free(),{high:r,low:i}}var v=(e,t,r=new n.Matrix4)=>{r.multiplyMatrices(t,e);let i=r.elements;return i[12]=0,i[13]=0,i[14]=0,r};function y(e,t,r=new n.Vector3,i=new n.Matrix4){i.multiplyMatrices(e,t),r.setFromMatrixPosition(i);let a=i.elements;return a[12]=0,a[13]=0,a[14]=0,{position:r,rotationScale:i}}var b=new n.Matrix4,x=new n.Vector3,S=(e,r)=>{b.copy(r).invert(),x.copy(e).applyMatrix4(b);let i=(0,t.encodePosition)(x.x,x.y,x.z),a=i.high,o=i.low,s={high:new n.Vector3(a.x,a.y,a.z),low:new n.Vector3(o.x,o.y,o.z)};return i.free(),s},C=class{_raw;constructor(e,n){this._raw=new t.EllipsoidGeodesic(new t.LLE(e.lat,e.lng,e.height),new t.LLE(n.lat,n.lng,n.height))}get distance(){return this._raw.distance}get converged(){return this._raw.converged}get startHeading(){return
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@navaramap/engine-api"),require("three")):typeof define==`function`&&define.amd?define([`exports`,`@navaramap/engine-api`,`three`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.NavaraThreeApi={},e._navaramap_engine_api,e.three))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:r(s(e)),l(t||!e||!e.__esModule||!c.call(e,`default`)?i(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function u(){return new n.Matrix4().makeRotationY(Math.PI/2)}function d(e,t){let r=new n.Matrix4().multiplyMatrices(e,new n.Matrix4().makeRotationFromEuler(new n.Euler(-n.MathUtils.degToRad(t.pitch??0),-n.MathUtils.degToRad(t.heading??0),n.MathUtils.degToRad(t.roll??0),`YXZ`)));if(t.scale!==void 0){let e=t.scale;r.scale(typeof e==`number`?new n.Vector3(e,e,e):new n.Vector3(e.x,e.y,e.z))}return r}function f(e,r){let i=new t.Vec3(e.x,e.y,e.z),a=new t.Vec3(r.x,r.y,r.z),o=(0,t.getPlaneFromPointNormal)(i,a),s=new n.Vector3(o.normal.x,o.normal.y,o.normal.z),c=new n.Plane(s,-o.distance);return o.free(),c}function p(e,r,i){let a=new t.Window(e.width,e.height,e.pixelRatio);a.width*=a.pixelRatio,a.height*=a.pixelRatio;let o=new t.Transform(r.position.x,r.position.y,r.position.z,r.quaternion.x,r.quaternion.y,r.quaternion.z,r.quaternion.w,r.scale.x,r.scale.y,r.scale.z),s=new t.CameraFrustum(r.near,r.far,(0,t.angleToRadian)(r.fov),r.aspect),c=(0,t.getPickRay)(a,o,s,new t.Vec2(i.x,i.y)),l=new n.Vector3(c.origin.x,c.origin.y,c.origin.z),u=new n.Vector3(c.direction.x,c.direction.y,c.direction.z),d=new n.Ray(l,u);return c.free(),d}function m(e,r){let i=new t.Ray(new t.Vec3(e.origin.x,e.origin.y,e.origin.z),new t.Vec3(e.direction.x,e.direction.y,e.direction.z)),a=(0,t.getPlaneFromPointNormal)(new t.Vec3(r.normal.x*-r.constant,r.normal.y*-r.constant,r.normal.z*-r.constant),new t.Vec3(r.normal.x,r.normal.y,r.normal.z)),o=(0,t.getRayPlaneIntersection)(i,a);if(o){let e=new n.Vector3(o.x,o.y,o.z);return o.free(),e}}function h(e){let n=new t.Vec3(e.x,e.y,e.z);return(0,t.getHeightFromEllipsoid)(n)}var g=Object.freeze({value:1});function _(e,r=new n.Vector3,i=new n.Vector3){let a=(0,t.encodePosition)(e.x,e.y,e.z);return r.set(a.high.x,a.high.y,a.high.z),i.set(a.low.x,a.low.y,a.low.z),a.free(),{high:r,low:i}}var v=(e,t,r=new n.Matrix4)=>{r.multiplyMatrices(t,e);let i=r.elements;return i[12]=0,i[13]=0,i[14]=0,r};function y(e,t,r=new n.Vector3,i=new n.Matrix4){i.multiplyMatrices(e,t),r.setFromMatrixPosition(i);let a=i.elements;return a[12]=0,a[13]=0,a[14]=0,{position:r,rotationScale:i}}var b=new n.Matrix4,x=new n.Vector3,S=(e,r)=>{b.copy(r).invert(),x.copy(e).applyMatrix4(b);let i=(0,t.encodePosition)(x.x,x.y,x.z),a=i.high,o=i.low,s={high:new n.Vector3(a.x,a.y,a.z),low:new n.Vector3(o.x,o.y,o.z)};return i.free(),s},C=class{_raw;constructor(e,n){this._raw=new t.EllipsoidGeodesic(new t.LLE((0,t.angleToRadian)(e.lat),(0,t.angleToRadian)(e.lng),e.height),new t.LLE((0,t.angleToRadian)(n.lat),(0,t.angleToRadian)(n.lng),n.height))}get distance(){return this._raw.distance}get converged(){return this._raw.converged}get startHeading(){return(0,t.angleToDegree)(this._raw.start_heading)}get endHeading(){return(0,t.angleToDegree)(this._raw.end_heading)}get start(){let e=this._raw.start;return{lat:(0,t.angleToDegree)(e.lat),lng:(0,t.angleToDegree)(e.lng),height:e.height}}get end(){let e=this._raw.end;return{lat:(0,t.angleToDegree)(e.lat),lng:(0,t.angleToDegree)(e.lng),height:e.height}}interpolatePoints(e){let n=this._raw.interpolateGeodeticPoints(e??null),r=[];for(let e of n)r.push({lat:(0,t.angleToDegree)(e.lat),lng:(0,t.angleToDegree)(e.lng),height:e.height}),e.free();return r}interpolateDistance(e){let n=this._raw.interpolateDistance(e),r={lat:(0,t.angleToDegree)(n.lat),lng:(0,t.angleToDegree)(n.lng),height:n.height};return n.free(),r}dispose(){this._raw.free()}};async function w(){await(0,t.default)()}function T(e){let r=(0,t.geodeticToXyz)(new t.LLE((0,t.angleToRadian)(e.lat),(0,t.angleToRadian)(e.lng),e.height)),i=new n.Vector3(r.x,r.y,r.z);return r.free(),i}function E(e){let n=new t.Vec3(e.x,e.y,e.z),r=(0,t.xyzToGeodetic)(n),i={lat:(0,t.angleToDegree)(r.lat),lng:(0,t.angleToDegree)(r.lng),height:r.height};return r.free(),i}function D(e){return(0,t.angleToRadian)(e)}function O(e){return(0,t.angleToDegree)(e)}function k(e,r,i){let a=new t.Window(e.width,e.height,e.pixelRatio);a.width*=a.pixelRatio,a.height*=a.pixelRatio;let o=new t.Transform(r.position.x,r.position.y,r.position.z,r.quaternion.x,r.quaternion.y,r.quaternion.z,r.quaternion.w,r.scale.x,r.scale.y,r.scale.z),s=new t.CameraFrustum(r.near,r.far,(0,t.angleToRadian)(r.fov),r.aspect),c=(0,t.screenToWorld)(a,o,s,new t.Vec2(i.x,i.y));if(!c)return;let l=new n.Vector3(c.x,c.y,c.z);return c.free(),l}function A(e){let r=(0,t.geodeticSurfaceNormal)(new t.LLE((0,t.angleToRadian)(e.lat),(0,t.angleToRadian)(e.lng),e.height)),i=new n.Vector3(r.x,r.y,r.z);return r.free(),i}function j(e){let r=new t.Vec3(e.x,e.y,e.z),i=(0,t.eastNorthUpToFixedFrame)(r);return new n.Matrix4().fromArray(i)}function M(e){let r=new t.Vec3(e.x,e.y,e.z),i=(0,t.northEastDownToFixedFrame)(r);return new n.Matrix4().fromArray(i)}function N(e){let r=new t.Vec3(e.x,e.y,e.z),i=(0,t.northUpEastToFixedFrame)(r);return new n.Matrix4().fromArray(i)}function P(e){let r=new t.Vec3(e.x,e.y,e.z),i=(0,t.northWestUpToFixedFrame)(r);return new n.Matrix4().fromArray(i)}function F(e){return N(e).multiply(u())}function I(e){return d(F(T({lng:e.lng,lat:e.lat,height:e.height??0})),e)}function L(e,r,i){let a=new t.Window(e.width,e.height,e.pixelRatio);a.width*=a.pixelRatio,a.height*=a.pixelRatio;let o=new t.Transform(r.position.x,r.position.y,r.position.z,r.quaternion.x,r.quaternion.y,r.quaternion.z,r.quaternion.w,r.scale.x,r.scale.y,r.scale.z),s=new t.CameraFrustum(r.near,r.far,(0,t.angleToRadian)(r.fov),r.aspect),c=(0,t.worldToScreen)(a,o,s,new t.Vec3(i.x,i.y,i.z));if(!c)return;let l=new n.Vector2(c.x,c.y);return c.free(),l}function R(){return(0,t.getWGS84SemiMajorAxis)()}function z(){return(0,t.getWGS84SemiMinorAxis)()}function B(){return(0,t.getWGS84EccentricitySquared)()}function V(){return(0,t.getWGS84Flattening)()}function H(){return(0,t.getWGS84Eccentricity)()}e.EllipsoidGeodesic=C,e.RTE_ONE_UNIFORM=g,e.calcCameraPosition=S,e.calcModelMatrixRTE=v,e.composeWorldMatrixForRTE=y,e.convertScreenToWorld=k,e.convertWorldToScreen=L,e.degreeToRadian=D,e.eastNorthUpToFixedFrame=j,e.encodePositionRTE=_,e.geodeticSurfaceNormal=A,e.geodeticToVector3=T,e.getHeightFromEllipsoid=h,e.getPickRay=p,e.getPlaneFromPointNormal=f,e.getRayPlaneIntersection=m,e.getWGS84Eccentricity=H,e.getWGS84EccentricitySquared=B,e.getWGS84Flattening=V,e.getWGS84SemiMajorAxis=R,e.getWGS84SemiMinorAxis=z,e.headingPitchRollToFixedFrame=I,e.initNavaraApi=w,e.northEastDownToFixedFrame=M,e.northUpEastToFixedFrame=N,e.northWestUpToFixedFrame=P,e.radianToDegree=O,e.vector3ToGeodetic=E,e.westUpNorthToFixedFrame=F});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navaramap/three-api",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"main": "dist/index.umd.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"three": ">=0.183.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@navaramap/core": "0.
|
|
26
|
-
"@navaramap/engine-api": "0.
|
|
25
|
+
"@navaramap/core": "0.1.1",
|
|
26
|
+
"@navaramap/engine-api": "0.1.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/three": "0.185.1",
|
package/src/ellipsoidGeodesic.ts
CHANGED
|
@@ -2,17 +2,21 @@ import type { LatLngHeight } from "@navaramap/core";
|
|
|
2
2
|
import {
|
|
3
3
|
EllipsoidGeodesic as EllipsoidGeodesicImpl,
|
|
4
4
|
LLE,
|
|
5
|
+
angleToRadian,
|
|
6
|
+
angleToDegree,
|
|
5
7
|
} from "@navaramap/engine-api";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Wrapper class for geodesic calculations on an ellipsoid surface.
|
|
9
11
|
* Precomputes common variables for optimization when instantiated.
|
|
10
12
|
*
|
|
13
|
+
* All latitudes/longitudes and headings are in **degrees**.
|
|
14
|
+
*
|
|
11
15
|
* @example
|
|
12
16
|
* ```typescript
|
|
13
17
|
* const geodesic = new EllipsoidGeodesic(
|
|
14
|
-
* { lat:
|
|
15
|
-
* { lat:
|
|
18
|
+
* { lat: 35.6812, lng: 139.7671, height: 0 },
|
|
19
|
+
* { lat: 34.7025, lng: 135.4959, height: 0 }
|
|
16
20
|
* );
|
|
17
21
|
*
|
|
18
22
|
* console.log(geodesic.distance);
|
|
@@ -27,13 +31,13 @@ export class EllipsoidGeodesic {
|
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Create a new geodesic between two points on the ellipsoid.
|
|
30
|
-
* @param start - Start point in geodetic coordinates (lat/lng in
|
|
31
|
-
* @param end - End point in geodetic coordinates (lat/lng in
|
|
34
|
+
* @param start - Start point in geodetic coordinates (lat/lng in degrees)
|
|
35
|
+
* @param end - End point in geodetic coordinates (lat/lng in degrees)
|
|
32
36
|
*/
|
|
33
37
|
constructor(start: LatLngHeight, end: LatLngHeight) {
|
|
34
38
|
this._raw = new EllipsoidGeodesicImpl(
|
|
35
|
-
new LLE(start.lat, start.lng, start.height),
|
|
36
|
-
new LLE(end.lat, end.lng, end.height),
|
|
39
|
+
new LLE(angleToRadian(start.lat), angleToRadian(start.lng), start.height),
|
|
40
|
+
new LLE(angleToRadian(end.lat), angleToRadian(end.lng), end.height),
|
|
37
41
|
);
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -52,32 +56,40 @@ export class EllipsoidGeodesic {
|
|
|
52
56
|
return this._raw.converged;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
/** Heading at the start point in
|
|
59
|
+
/** Heading at the start point in degrees */
|
|
56
60
|
get startHeading(): number {
|
|
57
|
-
return this._raw.start_heading;
|
|
61
|
+
return angleToDegree(this._raw.start_heading);
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
/** Heading at the end point in
|
|
64
|
+
/** Heading at the end point in degrees */
|
|
61
65
|
get endHeading(): number {
|
|
62
|
-
return this._raw.end_heading;
|
|
66
|
+
return angleToDegree(this._raw.end_heading);
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
/** Start point in geodetic coordinates */
|
|
69
|
+
/** Start point in geodetic coordinates (lat/lng in degrees) */
|
|
66
70
|
get start(): LatLngHeight {
|
|
67
71
|
const lle = this._raw.start;
|
|
68
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
lat: angleToDegree(lle.lat),
|
|
74
|
+
lng: angleToDegree(lle.lng),
|
|
75
|
+
height: lle.height,
|
|
76
|
+
};
|
|
69
77
|
}
|
|
70
78
|
|
|
71
|
-
/** End point in geodetic coordinates */
|
|
79
|
+
/** End point in geodetic coordinates (lat/lng in degrees) */
|
|
72
80
|
get end(): LatLngHeight {
|
|
73
81
|
const lle = this._raw.end;
|
|
74
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
lat: angleToDegree(lle.lat),
|
|
84
|
+
lng: angleToDegree(lle.lng),
|
|
85
|
+
height: lle.height,
|
|
86
|
+
};
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
/**
|
|
78
90
|
* Interpolate points along the geodesic path.
|
|
79
91
|
* @param granularity - Distance between interpolated points in meters (optional)
|
|
80
|
-
* @returns Array of interpolated points in geodetic coordinates
|
|
92
|
+
* @returns Array of interpolated points in geodetic coordinates (lat/lng in degrees)
|
|
81
93
|
*/
|
|
82
94
|
interpolatePoints(granularity?: number): LatLngHeight[] {
|
|
83
95
|
const wasmPoints = this._raw.interpolateGeodeticPoints(granularity ?? null);
|
|
@@ -85,8 +97,8 @@ export class EllipsoidGeodesic {
|
|
|
85
97
|
const results: LatLngHeight[] = [];
|
|
86
98
|
for (const point of wasmPoints) {
|
|
87
99
|
results.push({
|
|
88
|
-
lat: point.lat,
|
|
89
|
-
lng: point.lng,
|
|
100
|
+
lat: angleToDegree(point.lat),
|
|
101
|
+
lng: angleToDegree(point.lng),
|
|
90
102
|
height: point.height,
|
|
91
103
|
});
|
|
92
104
|
point.free();
|
|
@@ -98,14 +110,14 @@ export class EllipsoidGeodesic {
|
|
|
98
110
|
/**
|
|
99
111
|
* Interpolate a point at a specific distance along the geodesic path.
|
|
100
112
|
* @param distance - Distance from start point in meters
|
|
101
|
-
* @returns Interpolated point in geodetic coordinates
|
|
113
|
+
* @returns Interpolated point in geodetic coordinates (lat/lng in degrees)
|
|
102
114
|
*/
|
|
103
115
|
interpolateDistance(distance: number): LatLngHeight {
|
|
104
116
|
const wasmPoint = this._raw.interpolateDistance(distance);
|
|
105
117
|
|
|
106
118
|
const result: LatLngHeight = {
|
|
107
|
-
lat: wasmPoint.lat,
|
|
108
|
-
lng: wasmPoint.lng,
|
|
119
|
+
lat: angleToDegree(wasmPoint.lat),
|
|
120
|
+
lng: angleToDegree(wasmPoint.lng),
|
|
109
121
|
height: wasmPoint.height,
|
|
110
122
|
};
|
|
111
123
|
|
package/src/index.test.ts
CHANGED
|
@@ -28,6 +28,8 @@ vi.mock("@navaramap/engine-api", () => {
|
|
|
28
28
|
default: vi.fn(),
|
|
29
29
|
LLE,
|
|
30
30
|
Vec3,
|
|
31
|
+
angleToRadian: (deg: number) => (deg * Math.PI) / 180,
|
|
32
|
+
angleToDegree: (rad: number) => (rad * 180) / Math.PI,
|
|
31
33
|
// Transparent model: the rotation is pinned to the NUE basis at
|
|
32
34
|
// lng 0 / lat 0 (column-major: x = north (0,0,1), y = up (1,0,0),
|
|
33
35
|
// z = east (0,1,0)), but the ORIGIN is threaded through from the
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ import initApi, {
|
|
|
23
23
|
getWGS84Flattening as nvGetWGS84Flattening,
|
|
24
24
|
getWGS84Eccentricity as nvGetWGS84Eccentricity,
|
|
25
25
|
} from "@navaramap/engine-api";
|
|
26
|
-
import { Vector3, Vector2, Matrix4,
|
|
26
|
+
import { Vector3, Vector2, Matrix4, PerspectiveCamera } from "three";
|
|
27
27
|
|
|
28
28
|
import {
|
|
29
29
|
composeHeadingPitchRoll,
|
|
@@ -56,11 +56,13 @@ export async function initNavaraApi() {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Converts geodetic coordinates (longitude, latitude, height) to a Cartesian Vector3 in ECEF coordinates.
|
|
59
|
-
* @param lle - Geodetic coordinates (lng in
|
|
59
|
+
* @param lle - Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
60
60
|
* @returns Cartesian Vector3 in Earth-Centered Earth-Fixed (ECEF) coordinates
|
|
61
61
|
*/
|
|
62
62
|
export function geodeticToVector3(lle: LatLngHeight): Vector3 {
|
|
63
|
-
const pos = geodeticToXyz(
|
|
63
|
+
const pos = geodeticToXyz(
|
|
64
|
+
new LLE(angleToRadian(lle.lat), angleToRadian(lle.lng), lle.height),
|
|
65
|
+
);
|
|
64
66
|
const result = new Vector3(pos.x, pos.y, pos.z);
|
|
65
67
|
pos.free();
|
|
66
68
|
return result;
|
|
@@ -69,12 +71,16 @@ export function geodeticToVector3(lle: LatLngHeight): Vector3 {
|
|
|
69
71
|
/**
|
|
70
72
|
* Converts a Cartesian Vector3 in ECEF coordinates to geodetic coordinates.
|
|
71
73
|
* @param xyz - Cartesian Vector3 in Earth-Centered Earth-Fixed (ECEF) coordinates
|
|
72
|
-
* @returns Geodetic coordinates (lng in
|
|
74
|
+
* @returns Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
73
75
|
*/
|
|
74
76
|
export function vector3ToGeodetic(xyz: Vector3): LatLngHeight {
|
|
75
77
|
const vec3 = new Vec3(xyz.x, xyz.y, xyz.z);
|
|
76
78
|
const lle = xyzToGeodetic(vec3);
|
|
77
|
-
const result = {
|
|
79
|
+
const result = {
|
|
80
|
+
lat: angleToDegree(lle.lat),
|
|
81
|
+
lng: angleToDegree(lle.lng),
|
|
82
|
+
height: lle.height,
|
|
83
|
+
};
|
|
78
84
|
lle.free();
|
|
79
85
|
return result;
|
|
80
86
|
}
|
|
@@ -155,11 +161,13 @@ export function convertScreenToWorld(
|
|
|
155
161
|
|
|
156
162
|
/**
|
|
157
163
|
* Computes the surface normal vector at a geodetic position on the WGS84 ellipsoid.
|
|
158
|
-
* @param lle - Geodetic coordinates (lng in
|
|
164
|
+
* @param lle - Geodetic coordinates (lng in degrees, lat in degrees, height in meters)
|
|
159
165
|
* @returns Unit normal vector pointing outward from the ellipsoid surface
|
|
160
166
|
*/
|
|
161
167
|
export function geodeticSurfaceNormal(lle: LatLngHeight): Vector3 {
|
|
162
|
-
const pos = nvGeodeticSurfaceNormal(
|
|
168
|
+
const pos = nvGeodeticSurfaceNormal(
|
|
169
|
+
new LLE(angleToRadian(lle.lat), angleToRadian(lle.lng), lle.height),
|
|
170
|
+
);
|
|
163
171
|
const result = new Vector3(pos.x, pos.y, pos.z);
|
|
164
172
|
pos.free();
|
|
165
173
|
return result;
|
|
@@ -240,7 +248,6 @@ export function westUpNorthToFixedFrame(origin: Vector3): Matrix4 {
|
|
|
240
248
|
* engines differ in which axis they treat as an asset's front, so a model
|
|
241
249
|
* ported from one may need a multiple of 90° added to its heading.
|
|
242
250
|
*
|
|
243
|
-
* NOTE: unlike {@link geodeticToVector3} and the other helpers in this module,
|
|
244
251
|
* `lng`/`lat` and all angles here are in **degrees**, matching
|
|
245
252
|
* `setCamera` and the `geodetic` mesh Descriptor field.
|
|
246
253
|
*
|
|
@@ -254,8 +261,8 @@ export function headingPitchRollToFixedFrame(
|
|
|
254
261
|
placement: Omit<GeodeticPlacement, "heightReference">,
|
|
255
262
|
): Matrix4 {
|
|
256
263
|
const origin = geodeticToVector3({
|
|
257
|
-
lng:
|
|
258
|
-
lat:
|
|
264
|
+
lng: placement.lng,
|
|
265
|
+
lat: placement.lat,
|
|
259
266
|
height: placement.height ?? 0,
|
|
260
267
|
});
|
|
261
268
|
return composeHeadingPitchRoll(westUpNorthToFixedFrame(origin), placement);
|