@idm-plugin/geo 1.0.5 → 1.0.7
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/dist/index.d.ts +2 -1
- package/dist/index.js +681 -149
- package/dist/index.umd.cjs +1 -1
- package/dist/lane/src/index.d.ts +263 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as g from "@turf/turf";
|
|
2
|
+
import v from "moment";
|
|
2
3
|
import "moment-timezone";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
class u {
|
|
4
|
+
import R from "tz-lookup";
|
|
5
|
+
class l {
|
|
6
6
|
/**
|
|
7
7
|
* 基于输入的经度,计算出时区
|
|
8
8
|
* @param lng
|
|
9
9
|
* @param lat
|
|
10
10
|
*/
|
|
11
11
|
static guessTimeZoneOffset(e, t) {
|
|
12
|
-
const
|
|
12
|
+
const n = R(t, e), s = v().tz(n).utcOffset();
|
|
13
13
|
return this.roundPrecision(s / 60, 1);
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -18,22 +18,22 @@ class u {
|
|
|
18
18
|
* @return timezone => +08:30
|
|
19
19
|
*/
|
|
20
20
|
static prettyTimeZoneOffset(e) {
|
|
21
|
-
let t = Math.floor(Math.abs(e)),
|
|
22
|
-
return
|
|
21
|
+
let t = Math.floor(Math.abs(e)), n = Math.round((Math.abs(e) - t) * 60);
|
|
22
|
+
return n = n > 9 ? n : `0${n}`, t = t > 9 ? t : `0${t}`, e > 0 ? `+${t}:${n}` : `-${t}:${n}`;
|
|
23
23
|
}
|
|
24
|
-
static lng2pretty(e, t = 6,
|
|
25
|
-
e =
|
|
24
|
+
static lng2pretty(e, t = 6, n = "H°M′") {
|
|
25
|
+
e = l.convertToStdLng(e, t);
|
|
26
26
|
let s = "E";
|
|
27
|
-
e < 0 && (s = "W"), e = Math.abs(e),
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
const
|
|
27
|
+
e < 0 && (s = "W"), e = Math.abs(e), n = n.toUpperCase();
|
|
28
|
+
let o = e * 3600, i, r, c, a, d, u;
|
|
29
|
+
i = o % 3600 % 60, n.indexOf("S") !== -1 && (o = o - i, r = l.padNumber(i, 2, 2)), c = o / 60 % 60, n.indexOf("M") !== -1 && (n.indexOf("S") !== -1 ? a = l.roundPrecision(c, t).toString().padStart(2, "0") : a = l.padNumber(c, 2, 2), o = o - c * 60), d = o / 3600, n.indexOf("M") !== -1 ? u = l.roundPrecision(d, t).toString().padStart(3, "0") : u = l.padNumber(d, 3, 2);
|
|
30
|
+
const f = `${n.replace(/S+/gi, r).replace(/M+/gi, a).replace(/H+/gi, u)}${s}`;
|
|
31
31
|
return {
|
|
32
32
|
direction: s,
|
|
33
|
-
degree:
|
|
34
|
-
minute:
|
|
35
|
-
second:
|
|
36
|
-
pretty:
|
|
33
|
+
degree: l.roundPrecision(d, t),
|
|
34
|
+
minute: l.roundPrecision(c, t),
|
|
35
|
+
second: l.roundPrecision(i, t),
|
|
36
|
+
pretty: f
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -42,71 +42,71 @@ class u {
|
|
|
42
42
|
* @param precision 精确度
|
|
43
43
|
* @param format 格式化
|
|
44
44
|
*/
|
|
45
|
-
static lat2pretty(e, t = 6,
|
|
45
|
+
static lat2pretty(e, t = 6, n = "H°M′") {
|
|
46
46
|
e = e % 180;
|
|
47
47
|
let s = "N";
|
|
48
|
-
e < 0 && (s = "S"), e = Math.abs(e),
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
const
|
|
48
|
+
e < 0 && (s = "S"), e = Math.abs(e), n = n.toUpperCase();
|
|
49
|
+
let o = e * 3600, i, r, c, a, d, u;
|
|
50
|
+
i = o % 3600 % 60, n.indexOf("S") !== -1 && (o = o - i, r = l.padNumber(i, 2, 2)), c = o / 60 % 60, n.indexOf("M") !== -1 && (n.indexOf("S") !== -1 ? a = l.roundPrecision(c, t).toString().padStart(2, "0") : a = l.padNumber(c, 2, 2), o = o - c * 60), d = o / 3600, n.indexOf("M") !== -1 ? u = l.roundPrecision(d, t).toString().padStart(2, "0") : u = l.padNumber(d, 2, 2);
|
|
51
|
+
const f = `${n.replace(/S+/gi, r).replace(/M+/gi, a).replace(/H+/gi, u)}${s}`;
|
|
52
52
|
return {
|
|
53
53
|
direction: s,
|
|
54
|
-
degree:
|
|
55
|
-
minute:
|
|
56
|
-
second:
|
|
57
|
-
pretty:
|
|
54
|
+
degree: l.roundPrecision(d, t),
|
|
55
|
+
minute: l.roundPrecision(c, t),
|
|
56
|
+
second: l.roundPrecision(i, t),
|
|
57
|
+
pretty: f
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
static str2Lng(e, t = 6) {
|
|
61
|
-
let
|
|
61
|
+
let n;
|
|
62
62
|
if (isNaN(e)) {
|
|
63
|
-
e =
|
|
63
|
+
e = l.strReplace(e, "LNG");
|
|
64
64
|
const s = e[e.length - 1].toUpperCase();
|
|
65
65
|
e = e.substring(0, e.length - 1).trim();
|
|
66
|
-
const
|
|
67
|
-
let [
|
|
68
|
-
if (
|
|
69
|
-
const c = this.roundPrecision(
|
|
70
|
-
|
|
66
|
+
const o = e.split(" ").filter((c) => c !== "").map((c) => Number(c));
|
|
67
|
+
let [i, r] = o;
|
|
68
|
+
if (i > 360 && !r) {
|
|
69
|
+
const c = this.roundPrecision(i / 100, 0);
|
|
70
|
+
r = i - c * 100, i = c;
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
n = i + (r ?? 0) / 60, s === "W" && (n = n * -1);
|
|
73
73
|
} else
|
|
74
|
-
|
|
75
|
-
return
|
|
74
|
+
n = Number(e);
|
|
75
|
+
return l.convertToStdLng(n, t);
|
|
76
76
|
}
|
|
77
77
|
static str2Lat(e, t = 6) {
|
|
78
|
-
let
|
|
78
|
+
let n;
|
|
79
79
|
if (isNaN(e)) {
|
|
80
|
-
e =
|
|
80
|
+
e = l.strReplace(e, "LAT");
|
|
81
81
|
const s = e[e.length - 1].toUpperCase();
|
|
82
82
|
e = e.substring(0, e.length - 1).trim();
|
|
83
|
-
const
|
|
84
|
-
let [
|
|
85
|
-
if (
|
|
86
|
-
const c = this.roundPrecision(
|
|
87
|
-
|
|
83
|
+
const o = e.split(" ").filter((c) => c !== "").map((c) => Number(c));
|
|
84
|
+
let [i, r] = o;
|
|
85
|
+
if (i > 90 && !r) {
|
|
86
|
+
const c = this.roundPrecision(i / 100, 0);
|
|
87
|
+
r = i - c * 100, i = c;
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
n = i + (r ?? 0) / 60, s === "S" && (n = n * -1);
|
|
90
90
|
} else
|
|
91
|
-
|
|
92
|
-
return
|
|
91
|
+
n = Number(e);
|
|
92
|
+
return l.roundPrecision(n, t);
|
|
93
93
|
}
|
|
94
|
-
static str2LngOrLat(e, t = 6,
|
|
95
|
-
e =
|
|
94
|
+
static str2LngOrLat(e, t = 6, n = "LAT") {
|
|
95
|
+
e = l.strReplace(e, n);
|
|
96
96
|
const s = e[e.length - 1].toUpperCase();
|
|
97
97
|
return ["N", "S"].includes(s) ? {
|
|
98
|
-
lat:
|
|
98
|
+
lat: l.str2Lat(e, t)
|
|
99
99
|
} : {
|
|
100
|
-
lng:
|
|
100
|
+
lng: l.str2Lng(e, t)
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
static convertToStdLng(e, t = 4) {
|
|
104
|
-
return e > 180 ? (e = e % 360, e = e > 180 ? e - 360 : e) : e < -180 && (e = e % 360, e = e < -180 ? e + 360 : e),
|
|
104
|
+
return e > 180 ? (e = e % 360, e = e > 180 ? e - 360 : e) : e < -180 && (e = e % 360, e = e < -180 ? e + 360 : e), l.roundPrecision(e, t);
|
|
105
105
|
}
|
|
106
106
|
static roundPrecision(e, t = 4) {
|
|
107
107
|
if (typeof e == "number") {
|
|
108
|
-
const
|
|
109
|
-
return Math.round(e *
|
|
108
|
+
const n = Number("1".padEnd(t + 1, "0"));
|
|
109
|
+
return Math.round(e * n) / n;
|
|
110
110
|
}
|
|
111
111
|
return e;
|
|
112
112
|
}
|
|
@@ -130,12 +130,12 @@ class u {
|
|
|
130
130
|
}
|
|
131
131
|
static strReplace(e, t = "LAT") {
|
|
132
132
|
e = e.replace(/([0-9]+)\.([0-9]+\.[0-9]+)/g, "$1 $2").replace(/-/g, " ").replace(/°/, " ").replace(/'/g, " ").replace(/′/g, " ").replace(/"/g, " ").replace(/∼/g, " ").replace(/°/g, " ").replace(/,/g, ".").replace(/^ /g, "").replace(/ $/g, "").trim();
|
|
133
|
-
const
|
|
134
|
-
if (!["N", "S", "E", "W"].includes(
|
|
135
|
-
const s = e,
|
|
136
|
-
if (isNaN(
|
|
133
|
+
const n = e[e.length - 1].toUpperCase();
|
|
134
|
+
if (!["N", "S", "E", "W"].includes(n)) {
|
|
135
|
+
const s = e, o = Number(s.split(" ")[0]);
|
|
136
|
+
if (isNaN(o))
|
|
137
137
|
throw new Error(`invalid Lat/Lng: ${e}`);
|
|
138
|
-
|
|
138
|
+
o >= 90 ? e = `${s}E` : o <= -90 ? e = `${s}W` : ["LAN", "LNG"].includes(t == null ? void 0 : t.toUpperCase()) ? e = `${s}${o > 0 ? "E" : "W"}` : e = `${s}${o > 0 ? "N" : "S"}`;
|
|
139
139
|
}
|
|
140
140
|
return e;
|
|
141
141
|
}
|
|
@@ -146,158 +146,690 @@ class u {
|
|
|
146
146
|
* @param intPrecision 整数位数
|
|
147
147
|
* @param dcmPrecision 小数位数
|
|
148
148
|
*/
|
|
149
|
-
static padNumber(e, t = 2,
|
|
150
|
-
const s = Math.trunc(e).toString().padStart(t, "0"),
|
|
151
|
-
return `${s}.${
|
|
149
|
+
static padNumber(e, t = 2, n = 2) {
|
|
150
|
+
const s = Math.trunc(e).toString().padStart(t, "0"), o = Math.trunc(l.roundPrecision(e - Math.trunc(e), n) * Math.pow(10, n)).toString().padStart(n, "0");
|
|
151
|
+
return `${s}.${o}`;
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
class
|
|
154
|
+
class I {
|
|
155
155
|
static convert2Geojson(e) {
|
|
156
|
-
var
|
|
157
|
-
const t =
|
|
156
|
+
var n;
|
|
157
|
+
const t = g.featureCollection([]);
|
|
158
158
|
for (const s of e) {
|
|
159
159
|
if (s.forecasts) {
|
|
160
|
-
const
|
|
161
|
-
for (const
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
164
|
-
const
|
|
165
|
-
model:
|
|
160
|
+
const o = (n = s.history) == null ? void 0 : n[0];
|
|
161
|
+
for (const i of s.forecasts) {
|
|
162
|
+
const r = [], c = v(i.date).utc(), a = `${s.name}-${i.model}`;
|
|
163
|
+
if (o) {
|
|
164
|
+
const d = v(o.updated).utc(), u = g.point([o.lng, o.lat], {
|
|
165
|
+
model: i.model,
|
|
166
166
|
name: s.name,
|
|
167
|
-
date:
|
|
167
|
+
date: d.format(),
|
|
168
168
|
hour: 0,
|
|
169
|
-
format:
|
|
170
|
-
pressure:
|
|
171
|
-
wind: { kts:
|
|
172
|
-
category:
|
|
169
|
+
format: d.format("MMM-DD/HHmm[Z]"),
|
|
170
|
+
pressure: o.pressure > 1e4 ? l.roundPrecision(o.pressure / 100, 0) : l.roundPrecision(o.pressure, 0),
|
|
171
|
+
wind: { kts: o.kts, spd: o.speed || o.spd },
|
|
172
|
+
category: a,
|
|
173
173
|
type: "forecast"
|
|
174
174
|
});
|
|
175
|
-
t.features.push(
|
|
175
|
+
t.features.push(u), r.push(u.geometry.coordinates);
|
|
176
176
|
}
|
|
177
|
-
for (const
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
model:
|
|
177
|
+
for (const d in i == null ? void 0 : i.hours) {
|
|
178
|
+
const u = i.hours[d];
|
|
179
|
+
u.wind.spd = u.wind.spd || u.wind.speed;
|
|
180
|
+
const f = c.clone().add(Number(d), "hour"), p = g.point([u.lng, u.lat], {
|
|
181
|
+
model: i.model,
|
|
182
182
|
name: s.name,
|
|
183
|
-
date:
|
|
184
|
-
hour: Number(
|
|
185
|
-
format:
|
|
186
|
-
pressure:
|
|
187
|
-
gusts:
|
|
188
|
-
wind:
|
|
189
|
-
movement:
|
|
190
|
-
category:
|
|
183
|
+
date: f.format(),
|
|
184
|
+
hour: Number(d),
|
|
185
|
+
format: f.format("MMM-DD/HHmm[Z]"),
|
|
186
|
+
pressure: u.pressure > 1e4 ? l.roundPrecision(u.pressure / 100, 0) : l.roundPrecision(u.pressure, 0),
|
|
187
|
+
gusts: u.gusts,
|
|
188
|
+
wind: u.wind || {},
|
|
189
|
+
movement: u.movement,
|
|
190
|
+
category: a,
|
|
191
191
|
type: "forecast"
|
|
192
192
|
});
|
|
193
|
-
t.features.push(
|
|
193
|
+
t.features.push(p), r.push(p.geometry.coordinates);
|
|
194
194
|
}
|
|
195
|
-
if ((
|
|
196
|
-
const
|
|
197
|
-
date:
|
|
195
|
+
if ((r == null ? void 0 : r.length) > 1) {
|
|
196
|
+
const d = g.lineString(l.convertToMonotonicLng2(r), {
|
|
197
|
+
date: i.date,
|
|
198
198
|
id: s.id || s.name,
|
|
199
|
-
model:
|
|
199
|
+
model: i.model,
|
|
200
200
|
name: s.name,
|
|
201
|
-
category:
|
|
201
|
+
category: a,
|
|
202
202
|
type: "forecast"
|
|
203
203
|
});
|
|
204
|
-
t.features.push(
|
|
204
|
+
t.features.push(d);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
if (s.history) {
|
|
209
|
-
const
|
|
210
|
-
for (const
|
|
211
|
-
const c =
|
|
209
|
+
const o = [];
|
|
210
|
+
for (const r of s.history) {
|
|
211
|
+
const c = v(r.updated).utc(), a = g.point([r.lng, r.lat], {
|
|
212
212
|
name: s.name,
|
|
213
213
|
date: c.format(),
|
|
214
214
|
format: c.format("MMM-DD/HHmm[Z]"),
|
|
215
|
-
pressure:
|
|
216
|
-
spd:
|
|
217
|
-
kts:
|
|
218
|
-
source:
|
|
219
|
-
level:
|
|
215
|
+
pressure: r.pressure > 1e4 ? l.roundPrecision(r.pressure / 100, 0) : l.roundPrecision(r.pressure, 0),
|
|
216
|
+
spd: r.speed || r.spd,
|
|
217
|
+
kts: r.kts,
|
|
218
|
+
source: r.source,
|
|
219
|
+
level: r.type,
|
|
220
220
|
type: "history",
|
|
221
221
|
category: `${s.name}-history`
|
|
222
222
|
});
|
|
223
|
-
t.features.push(
|
|
223
|
+
t.features.push(a), o.push(a.geometry.coordinates);
|
|
224
224
|
}
|
|
225
|
-
const
|
|
226
|
-
if (
|
|
227
|
-
const
|
|
225
|
+
const i = s.history[0];
|
|
226
|
+
if (o.length === 1 && o.push(o[0]), o.length > 1) {
|
|
227
|
+
const r = g.lineString(l.convertToMonotonicLng2(o), {
|
|
228
228
|
name: s.name,
|
|
229
229
|
type: "history",
|
|
230
|
-
updated:
|
|
231
|
-
pressure: (
|
|
232
|
-
spd: (
|
|
233
|
-
kts:
|
|
234
|
-
source:
|
|
235
|
-
level:
|
|
230
|
+
updated: i == null ? void 0 : i.updated,
|
|
231
|
+
pressure: (i == null ? void 0 : i.pressure) > 1e4 ? l.roundPrecision((i == null ? void 0 : i.pressure) / 100, 0) : l.roundPrecision(i == null ? void 0 : i.pressure, 0),
|
|
232
|
+
spd: (i == null ? void 0 : i.speed) || (i == null ? void 0 : i.spd),
|
|
233
|
+
kts: i == null ? void 0 : i.kts,
|
|
234
|
+
source: i == null ? void 0 : i.source,
|
|
235
|
+
level: i == null ? void 0 : i.type
|
|
236
236
|
});
|
|
237
|
-
t.features.push(
|
|
237
|
+
t.features.push(r);
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
return t;
|
|
242
242
|
}
|
|
243
243
|
static interpolate(e, t = 3) {
|
|
244
|
-
var
|
|
245
|
-
const
|
|
246
|
-
for (const
|
|
247
|
-
const
|
|
248
|
-
let
|
|
249
|
-
const b = (
|
|
250
|
-
(
|
|
244
|
+
var o, i, r, c;
|
|
245
|
+
const n = (o = e == null ? void 0 : e.data) == null ? void 0 : o.features.filter((a) => a.geometry.type === "LineString" && a.properties.type === "forecast"), s = [];
|
|
246
|
+
for (const a of n) {
|
|
247
|
+
const d = a.properties.name, u = a.properties.model, f = v(a.properties.date).utc();
|
|
248
|
+
let p = t * 60 - (f.get("hour") * 60 + f.get("minute")) % (t * 60);
|
|
249
|
+
const b = (i = e == null ? void 0 : e.data) == null ? void 0 : i.features.filter(
|
|
250
|
+
(m) => m.geometry.type === "Point" && m.properties.type === "forecast" && m.properties.category === `${d}-${u}`
|
|
251
251
|
);
|
|
252
|
-
let
|
|
253
|
-
for (;
|
|
254
|
-
if (
|
|
255
|
-
const
|
|
256
|
-
name:
|
|
257
|
-
model:
|
|
258
|
-
category:
|
|
259
|
-
date:
|
|
260
|
-
format:
|
|
261
|
-
gusts: this.computeNumber(
|
|
262
|
-
hour: this.computeNumber(
|
|
263
|
-
movement: this.computeNumber(
|
|
264
|
-
pressure: this.computeNumber(
|
|
265
|
-
wind: this.computeNumber(
|
|
252
|
+
let T, P = f.clone().add(p, "minute").set({ minute: 0, second: 0, millisecond: 0 });
|
|
253
|
+
for (; T = this.pickIndex(b, P), T <= b.length - 1; ) {
|
|
254
|
+
if (T > 0) {
|
|
255
|
+
const m = b[T], h = T === 0 ? void 0 : b[T - 1], S = (p / 60 - ((r = h == null ? void 0 : h.properties) == null ? void 0 : r.hour)) / (m.properties.hour - ((c = h == null ? void 0 : h.properties) == null ? void 0 : c.hour)), M = this.computeNumber(h == null ? void 0 : h.geometry.coordinates[0], m.geometry.coordinates[0], S), N = this.computeNumber(h == null ? void 0 : h.geometry.coordinates[1], m.geometry.coordinates[1], S), C = g.point([M, N], {
|
|
256
|
+
name: d,
|
|
257
|
+
model: u,
|
|
258
|
+
category: m == null ? void 0 : m.properties.category,
|
|
259
|
+
date: P.format(),
|
|
260
|
+
format: P.format("MMM-DD/HHmm[Z]"),
|
|
261
|
+
gusts: this.computeNumber(h == null ? void 0 : h.properties.gusts, m.properties.gusts, S),
|
|
262
|
+
hour: this.computeNumber(h == null ? void 0 : h.properties.hour, m.properties.hour, S),
|
|
263
|
+
movement: this.computeNumber(h == null ? void 0 : h.properties.movement, m.properties.movement, S),
|
|
264
|
+
pressure: this.computeNumber(h == null ? void 0 : h.properties.pressure, m.properties.pressure, S),
|
|
265
|
+
wind: this.computeNumber(h == null ? void 0 : h.properties.wind, m.properties.wind, S),
|
|
266
266
|
type: "forecast"
|
|
267
267
|
});
|
|
268
|
-
s.push(
|
|
268
|
+
s.push(C);
|
|
269
269
|
}
|
|
270
|
-
|
|
270
|
+
p += t * 60, P = f.clone().add(p, "minute").set({ minute: 0, second: 0, millisecond: 0 });
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
return s;
|
|
274
274
|
}
|
|
275
275
|
static pickIndex(e, t) {
|
|
276
|
-
let
|
|
276
|
+
let n = 0;
|
|
277
277
|
for (const s of e) {
|
|
278
|
-
if (
|
|
279
|
-
return
|
|
280
|
-
|
|
278
|
+
if (v(s.properties.date).isAfter(t))
|
|
279
|
+
return n === 0 ? -1 : n;
|
|
280
|
+
n++;
|
|
281
281
|
}
|
|
282
|
-
return
|
|
282
|
+
return n;
|
|
283
283
|
}
|
|
284
|
-
static computeNumber(e, t,
|
|
284
|
+
static computeNumber(e, t, n) {
|
|
285
285
|
if (e)
|
|
286
286
|
if (t) {
|
|
287
287
|
if (isNaN(e) && isNaN(t) && typeof e != "string" && typeof t != "string") {
|
|
288
288
|
const s = {};
|
|
289
|
-
for (const
|
|
290
|
-
s[
|
|
289
|
+
for (const o in e)
|
|
290
|
+
s[o] = this.computeNumber(e[o], t[o], n);
|
|
291
291
|
return s;
|
|
292
292
|
}
|
|
293
|
-
return Math.round((e + (t - e) *
|
|
293
|
+
return Math.round((e + (t - e) * n) * 100) / 100;
|
|
294
294
|
} else
|
|
295
295
|
return e;
|
|
296
296
|
else
|
|
297
297
|
return t;
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
|
+
class W {
|
|
301
|
+
/**
|
|
302
|
+
* 计算方位角
|
|
303
|
+
* @param from 坐标 {lng, lat}
|
|
304
|
+
* @param to 坐标 {lng, lat}
|
|
305
|
+
* @param rhumb true 横向方位角,false 大圆方位角
|
|
306
|
+
* @param precision
|
|
307
|
+
* @returns {number} 单位度
|
|
308
|
+
*/
|
|
309
|
+
static calculateBearing(e, t, n = !0, s = 4) {
|
|
310
|
+
const o = g.points([
|
|
311
|
+
[e.lng, e.lat],
|
|
312
|
+
[t.lng, t.lat]
|
|
313
|
+
]);
|
|
314
|
+
let i;
|
|
315
|
+
return n ? i = g.rhumbBearing(o.features[0], o.features[1]) : i = g.bearing(o.features[0], o.features[1]), i < 0 && (i += 360), l.roundPrecision(i, s);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 计算两点间距离
|
|
319
|
+
* @param from 坐标 {lng, lat}
|
|
320
|
+
* @param to 坐标 {lng, lat}
|
|
321
|
+
* @param rhumb true 横向距离,false 大圆距离
|
|
322
|
+
* @param precision
|
|
323
|
+
* @param units 单位,默认 nm(海里)
|
|
324
|
+
* @returns {number}
|
|
325
|
+
*/
|
|
326
|
+
static calculateDistance(e, t, n = !0, s = 4, o = "nauticalmiles") {
|
|
327
|
+
e = { ...e }, t = { ...t }, e.lng = l.convertToStdLng(e.lng, s), t.lng = l.convertToStdLng(t.lng, s);
|
|
328
|
+
const i = g.points([
|
|
329
|
+
[e.lng, e.lat],
|
|
330
|
+
[t.lng, t.lat]
|
|
331
|
+
]);
|
|
332
|
+
let r;
|
|
333
|
+
return n ? r = g.rhumbDistance(i.features[0], i.features[1], { units: o }) : r = g.distance(i.features[0], i.features[1], { units: o }), l.roundPrecision(r, s);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 计算航线距离
|
|
337
|
+
* @param route [[[lng, lat],[lng, lat]]]
|
|
338
|
+
* @param precision
|
|
339
|
+
* @param units
|
|
340
|
+
*/
|
|
341
|
+
static calculateRouteDistance(e, t = 4, n = "nauticalmiles") {
|
|
342
|
+
let s = 0, o;
|
|
343
|
+
for (const i of e)
|
|
344
|
+
for (let r = 0; r < i.length - 1; r++) {
|
|
345
|
+
const c = { lng: i[r][0], lat: i[r][1] };
|
|
346
|
+
r === 0 && o && (s += this.calculateDistance(o, c, !0, t, n));
|
|
347
|
+
const a = { lng: i[r + 1][0], lat: i[r + 1][1] };
|
|
348
|
+
s += this.calculateDistance(c, a, !0, t, n), o = a;
|
|
349
|
+
}
|
|
350
|
+
return l.roundPrecision(s, t);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* 计算坐标(基于方位角和距离)
|
|
354
|
+
* @param from 坐标 {lng, lat}
|
|
355
|
+
* @param bearing 方位角,单位度
|
|
356
|
+
* @param distance 距离
|
|
357
|
+
* @param units 单位,默认 nm(海里)
|
|
358
|
+
* @param rhumb
|
|
359
|
+
*/
|
|
360
|
+
static calculateCoordinate(e, t, n, s = "nauticalmiles", o = !0) {
|
|
361
|
+
const i = g.point([e.lng, e.lat]);
|
|
362
|
+
let r;
|
|
363
|
+
o ? r = g.rhumbDestination(i, n, t, { units: s }) : r = g.destination(i, n, t, { units: s });
|
|
364
|
+
const c = r.geometry.coordinates;
|
|
365
|
+
return { lng: l.convertToStdLng(c[0], 8), lat: l.roundPrecision(c[1], 8) };
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* 插值大圆坐标(基于两点方位角和间距)
|
|
369
|
+
* @param from 坐标 {lng, lat}
|
|
370
|
+
* @param to 坐标 {lng, lat}
|
|
371
|
+
* @param spacing 间距
|
|
372
|
+
* @param includeHead true 包含起点 from
|
|
373
|
+
* @param includeTail true 包含终点 to
|
|
374
|
+
* @param units 单位,默认 nm(海里)
|
|
375
|
+
*/
|
|
376
|
+
static interpolateCoordinates(e, t, n, s = !0, o = !0, i = "nauticalmiles") {
|
|
377
|
+
const r = [], c = this.calculateBearing(e, t, !1), a = this.calculateDistance(e, t, !1, 8, i);
|
|
378
|
+
s && r.push({ lng: e.lng, lat: e.lat });
|
|
379
|
+
let d = 0;
|
|
380
|
+
for (; d < a; )
|
|
381
|
+
d += n, d < a && r.push(this.calculateCoordinate(e, c, d, i, !1));
|
|
382
|
+
return o && r.push({ lng: t.lng, lat: t.lat }), r;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* 分组坐标(如相邻两个坐标经度差超180度,需以180为界将坐标分为两组)
|
|
386
|
+
* @param coordinates [{lng, lat}]
|
|
387
|
+
* @param rhumb
|
|
388
|
+
* @example
|
|
389
|
+
* coordinates: [{lng: 160,lat: 30}, {lng: 170, lat: 40},{lng: -170, lat: 40},{lng: -160, lat: 30}]
|
|
390
|
+
* @return [
|
|
391
|
+
* [[160, 30],[170,40]],
|
|
392
|
+
* [[-170,40],[-160,30]]
|
|
393
|
+
* ]
|
|
394
|
+
*/
|
|
395
|
+
static divideAccordingToLng(e, t = !1) {
|
|
396
|
+
if ((e == null ? void 0 : e.length) < 2)
|
|
397
|
+
return [];
|
|
398
|
+
e = this.deduplicateCoordinates(e);
|
|
399
|
+
let n = [];
|
|
400
|
+
const s = [];
|
|
401
|
+
let o, i;
|
|
402
|
+
for (let r = 0; r < e.length - 1; r++) {
|
|
403
|
+
o = l.convertToStdLng(e[r].lng, 8), i = l.convertToStdLng(e[r + 1].lng, 8), n.push([o, e[r].lat]);
|
|
404
|
+
const c = o - i;
|
|
405
|
+
if (Math.abs(c) > 180) {
|
|
406
|
+
const a = l.convertToMonotonicLng2([
|
|
407
|
+
[o, e[r].lat],
|
|
408
|
+
[i, e[r + 1].lat]
|
|
409
|
+
]);
|
|
410
|
+
let d, u;
|
|
411
|
+
t ? (d = g.lineString(a), u = g.lineString([
|
|
412
|
+
[c > 0 ? 180 : -180, 89],
|
|
413
|
+
[c > 0 ? 180 : -180, -89]
|
|
414
|
+
])) : (d = g.greatCircle(a[0], a[1]), u = g.greatCircle([c > 0 ? 180 : -180, 89], [c > 0 ? 180 : -180, -89]));
|
|
415
|
+
const f = g.lineIntersect(d, u);
|
|
416
|
+
let p;
|
|
417
|
+
if (f.features.length) {
|
|
418
|
+
const b = g.getCoord(f.features[0]);
|
|
419
|
+
p = l.roundPrecision(b[1], 8);
|
|
420
|
+
} else
|
|
421
|
+
p = e[r].lat;
|
|
422
|
+
c > 0 ? (n.push([180 - 1e-6, p]), s.push([...n]), n = [], n.push([-(180 - 1e-6), p])) : (n.push([-(180 - 1e-6), p]), s.push([...n]), n = [], n.push([180 - 1e-6, p]));
|
|
423
|
+
}
|
|
424
|
+
r === e.length - 2 && n.push([i, e[r + 1].lat]);
|
|
425
|
+
}
|
|
426
|
+
return s.push(n), s;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 去除重复坐标
|
|
430
|
+
* @param route
|
|
431
|
+
*/
|
|
432
|
+
static deduplicateRoute(e) {
|
|
433
|
+
const t = [];
|
|
434
|
+
for (const n of e) {
|
|
435
|
+
const s = n.reduce((o, i) => (o.findIndex((r) => r[0] === i[0] && r[1] === i[1]) === -1 && o.push(i), o), []);
|
|
436
|
+
t.push(s);
|
|
437
|
+
}
|
|
438
|
+
return t;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* 去除重新坐标
|
|
442
|
+
* @param coordinates
|
|
443
|
+
*/
|
|
444
|
+
static deduplicateCoordinates(e) {
|
|
445
|
+
return e.reduce((t, n) => (t.findIndex((s) => s.lat === n.lat && s.lng === n.lng) === -1 && t.push(n), t), []);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 移出坐标
|
|
449
|
+
* @param coordinate {lng, lat}
|
|
450
|
+
* @param route 航线[[[lng, lat],[lng, lat]]]
|
|
451
|
+
*/
|
|
452
|
+
static removeCoordinateFromRoute(e, t) {
|
|
453
|
+
e.lng = l.convertToStdLng(e.lng, 8);
|
|
454
|
+
for (const n of t)
|
|
455
|
+
for (let s = n.length - 1; s >= 0; s--)
|
|
456
|
+
l.roundPrecision(n[s][0], 8) === e.lng && l.roundPrecision(n[s][1], 8) === l.roundPrecision(e.lat, 8) && n.splice(s, 1);
|
|
457
|
+
return t;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* 移出坐标
|
|
461
|
+
* @param coordinate {lng, lat}
|
|
462
|
+
* @param waypoints [{lat, lng}, {lat, lng}]
|
|
463
|
+
*/
|
|
464
|
+
static removeCoordinateFromWaypoints(e, t) {
|
|
465
|
+
e.lng = l.convertToStdLng(e.lng, 8);
|
|
466
|
+
for (let n = t.length - 1; n >= 0; n--)
|
|
467
|
+
l.roundPrecision(t[n].lng, 8) === e.lng && l.roundPrecision(t[n].lat, 8) === l.roundPrecision(e.lat, 8) && t.splice(n, 1);
|
|
468
|
+
return t;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* 合并坐标进航线(基于坐标到线段最短距离边合并)
|
|
472
|
+
* @param coordinate 待合并的坐标 {lng, lat}
|
|
473
|
+
* @param route 航线[[[lng, lat],[lng, lat]]]
|
|
474
|
+
* @example
|
|
475
|
+
* coordinate {lng: 122, lat: 35}
|
|
476
|
+
*
|
|
477
|
+
* route: [[[120, 30], [125,40], [130, 37]], [[-150, 40], [-130, 30]]]
|
|
478
|
+
* @return
|
|
479
|
+
* [[[120, 30], [120, 35], [125,40], [130, 37]], [[-150, 40], [-130, 30]]]
|
|
480
|
+
*/
|
|
481
|
+
static mergeCoordinateToRoute(e, t) {
|
|
482
|
+
e.lng = l.convertToStdLng(e.lng, 8);
|
|
483
|
+
let n = Number.MAX_VALUE, s = 0, o = 0, i, r;
|
|
484
|
+
return t.forEach((c, a) => {
|
|
485
|
+
for (let d = 0; d < c.length - 1; d++) {
|
|
486
|
+
const u = { lng: c[d][0], lat: c[d][1] }, f = { lng: c[d + 1][0], lat: c[d + 1][1] }, p = this.calculatePointToLineDistance(e, u, f);
|
|
487
|
+
n > p && (n = p, o = d, s = a, i = this.calculateDistance(u, e), r = this.calculateDistance(f, e));
|
|
488
|
+
}
|
|
489
|
+
}), i !== 0 && r !== 0 ? t[s].splice(o + 1, 0, [e.lng, e.lat]) : i === 0 ? t[s].splice(o, 1, [e.lng, e.lat]) : r === 0 && t[s].splice(o + 1, 1, [e.lng, e.lat]), t;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* 合并多个waypoints进航线
|
|
493
|
+
* @param waypoints [{lat, lng}, {lat, lng}]
|
|
494
|
+
* @param route 航线 [[[lng, lat],[lng, lat]]]
|
|
495
|
+
*/
|
|
496
|
+
static mergeWaypointsToRoute(e, t) {
|
|
497
|
+
for (const n of e)
|
|
498
|
+
t = this.mergeCoordinateToRoute(n, t);
|
|
499
|
+
return t;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* 计算区间航线
|
|
503
|
+
* @param from {lng, lat}
|
|
504
|
+
* @param to {lng, lat}
|
|
505
|
+
* @param route [[[lng, lat]]]
|
|
506
|
+
* @return [[[lng, lat]]]
|
|
507
|
+
*/
|
|
508
|
+
static calculateRangeRoute(e, t, n) {
|
|
509
|
+
n = this.mergeWaypointsToRoute([e, t], n);
|
|
510
|
+
const s = [];
|
|
511
|
+
let o = 0;
|
|
512
|
+
return n.forEach((i) => {
|
|
513
|
+
if (o === 2)
|
|
514
|
+
return;
|
|
515
|
+
const r = [];
|
|
516
|
+
for (const c of i) {
|
|
517
|
+
if (l.roundPrecision(t.lng, 8) === l.roundPrecision(c[0], 8) && l.roundPrecision(t.lat, 8) === l.roundPrecision(c[1], 8)) {
|
|
518
|
+
r.push(c), o === 0 && r.push([e.lng, e.lat]), o = 2;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
o === 1 ? r.push(c) : l.roundPrecision(e.lng, 8) === l.roundPrecision(c[0], 8) && l.roundPrecision(e.lat, 8) === l.roundPrecision(c[1], 8) && (o = 1, r.push(c));
|
|
522
|
+
}
|
|
523
|
+
r.length && s.push(r);
|
|
524
|
+
}), s;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* 计算from到to之间的航线
|
|
528
|
+
* @param from {lng, lat}
|
|
529
|
+
* @param to {lng, lat}
|
|
530
|
+
* @param route [[[lng, lat]]]
|
|
531
|
+
* @param waypoints
|
|
532
|
+
* @return [{lng, lat}]
|
|
533
|
+
*/
|
|
534
|
+
static calculateRangeWaypoints(e, t, n, s = []) {
|
|
535
|
+
const o = this.convertRouteToCoordinates(n, 0), i = this.mergeCoordinatesToWaypoints([e, t, ...s], o), r = i.findIndex(
|
|
536
|
+
(d) => l.roundPrecision(e.lng, 8) === l.roundPrecision(d.lng, 8) && l.roundPrecision(e.lat, 8) === l.roundPrecision(d.lat, 8)
|
|
537
|
+
), c = i.findIndex(
|
|
538
|
+
(d) => l.roundPrecision(t.lng, 8) === l.roundPrecision(d.lng, 8) && l.roundPrecision(t.lat, 8) === l.roundPrecision(d.lat, 8)
|
|
539
|
+
);
|
|
540
|
+
return i.filter((d, u) => u >= r && u <= c);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 计算坐标到航路上的最短距离
|
|
544
|
+
* @param from
|
|
545
|
+
* @param route
|
|
546
|
+
*/
|
|
547
|
+
static calculateMinDistanceToRoute(e, t) {
|
|
548
|
+
let n = Number.MAX_VALUE, s = 0, o = 0;
|
|
549
|
+
return t.forEach((i, r) => {
|
|
550
|
+
for (let c = 0; c < i.length - 1; c++) {
|
|
551
|
+
const a = { lng: i[c][0], lat: i[c][1] }, d = { lng: i[c + 1][0], lat: i[c + 1][1] }, u = this.calculatePointToLineDistance(e, a, d);
|
|
552
|
+
n > u && (n = u, s = c, o = r);
|
|
553
|
+
}
|
|
554
|
+
}), { minDist: n, segIndex: o, minIndex: s };
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* 计算子航线
|
|
558
|
+
* @param from {lng, lat} 起始位置
|
|
559
|
+
* @param route [[[lng, lat]]] 剩余航线
|
|
560
|
+
* @return [[[lng, lat]]]
|
|
561
|
+
*/
|
|
562
|
+
static calculateSubRoute(e, t) {
|
|
563
|
+
const { segIndex: n, minIndex: s } = this.calculateMinDistanceToRoute({ ...e }, t);
|
|
564
|
+
e.lng = l.convertToStdLng(e.lng);
|
|
565
|
+
const o = [];
|
|
566
|
+
let i = !0;
|
|
567
|
+
for (let r = n; r < t.length; r++)
|
|
568
|
+
if (i) {
|
|
569
|
+
const c = [];
|
|
570
|
+
c.push([e.lng, e.lat]);
|
|
571
|
+
for (let a = s + 1; a < t[r].length; a++)
|
|
572
|
+
e.lng === t[r][a][0] && e.lat === t[r][a][1] || c.push(t[r][a]);
|
|
573
|
+
o.push(c), i = !1;
|
|
574
|
+
} else
|
|
575
|
+
o.push([...t[r]]);
|
|
576
|
+
return o;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* 计算子途经点
|
|
580
|
+
* @param from {lng, lat} 起始位置
|
|
581
|
+
* @param waypoints [{lng, lat}]
|
|
582
|
+
* @return [{lng, lat}]
|
|
583
|
+
*/
|
|
584
|
+
static calculateSubWaypoints(e, t) {
|
|
585
|
+
let n = Number.MAX_VALUE, s = 0;
|
|
586
|
+
for (let i = 0; i < t.length - 1; i++) {
|
|
587
|
+
const r = t[i], c = t[i + 1];
|
|
588
|
+
if (this.calculateDistance(e, r) === 0)
|
|
589
|
+
return t;
|
|
590
|
+
if (this.calculateDistance(e, c) === 0)
|
|
591
|
+
return t.filter((d, u) => u > 0);
|
|
592
|
+
const a = this.calculatePointToLineDistance(e, r, c);
|
|
593
|
+
n > a && (n = a, s = i);
|
|
594
|
+
}
|
|
595
|
+
e.lng = l.convertToStdLng(e.lng);
|
|
596
|
+
const o = [e];
|
|
597
|
+
for (let i = s + 1; i < t.length; i++)
|
|
598
|
+
o.push(t[i]);
|
|
599
|
+
return o;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* 计算坐标到以(from, to)横向线上的距离
|
|
603
|
+
* @param coordinate { lng, lat }
|
|
604
|
+
* @param from { lng, lat }
|
|
605
|
+
* @param to { lng, lat }
|
|
606
|
+
* @param options
|
|
607
|
+
*/
|
|
608
|
+
static calculatePointToLineDistance(e, t, n, s = { units: "nauticalmiles", method: "geodesic" }) {
|
|
609
|
+
e.lng = l.convertToStdLng(e.lng), t = { ...t }, n = { ...n }, t.lng = l.convertToStdLng(t.lng, 8), n.lng = l.convertToStdLng(n.lng, 8);
|
|
610
|
+
const o = l.convertToMonotonicLng([t, n]);
|
|
611
|
+
t = o[0], n = o[1];
|
|
612
|
+
const i = g.lineString([
|
|
613
|
+
[t.lng, t.lat],
|
|
614
|
+
[n.lng, n.lat]
|
|
615
|
+
]), r = g.pointToLineDistance(g.point([e.lng, e.lat]), i, s), c = g.pointToLineDistance(g.point([e.lng > 0 ? e.lng - 360 : e.lng + 360, e.lat]), i, s);
|
|
616
|
+
return l.roundPrecision(Math.min(r, c), 6);
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* 计算途经点的COG, Distance等属性
|
|
620
|
+
* @param waypoints
|
|
621
|
+
* @param route
|
|
622
|
+
*/
|
|
623
|
+
static calculateWaypointsPropInRoute(e, t) {
|
|
624
|
+
t = this.mergeWaypointsToRoute(e, t);
|
|
625
|
+
for (let n = 0; n < e.length - 1; n++) {
|
|
626
|
+
const s = e[n], o = e[n + 1], i = this.calculateRangeRoute(s, o, t);
|
|
627
|
+
n === 0 && (s.distanceFromPrevious = 0, s.distanceFromStart = 0), o.distanceFromPrevious = this.calculateRouteDistance(i), o.distanceFromStart = l.roundPrecision((s.distanceFromStart || 0) + o.distanceFromPrevious);
|
|
628
|
+
}
|
|
629
|
+
return e;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* @param coordinates [{lng, lat}]
|
|
633
|
+
* @param waypoints [{lng, lat}]
|
|
634
|
+
* @param replace true replace the same waypoint with coordinate
|
|
635
|
+
*/
|
|
636
|
+
static mergeCoordinatesToWaypoints(e, t, n = !0) {
|
|
637
|
+
for (const s of e)
|
|
638
|
+
this.mergeCoordinateToWaypoints(s, t, n);
|
|
639
|
+
return t;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* 合并坐标进航路途经点
|
|
643
|
+
* @param coordinate 坐标 {lng, lat}
|
|
644
|
+
* @param waypoints 途经点 [{lng, lat}, {lng, lat}]
|
|
645
|
+
*
|
|
646
|
+
* @example
|
|
647
|
+
* coordinate: { lng: 179, lat: 50 }
|
|
648
|
+
* waypoints: [{ lng: 160, lat: 30}, { lng: 170, lat: 40}, {lng: -170, lat: 40}, {lng: -160, lat: 30}]
|
|
649
|
+
* @param replace true replace the same waypoint with coordinate
|
|
650
|
+
* @return
|
|
651
|
+
* [{ lng: 160, lat: 30}, { lng: 170, lat: 40}, {lng: 179, lat: 50}, {lng: -170, lat: 40}, {lng: -160, lat: 30}]
|
|
652
|
+
*/
|
|
653
|
+
static mergeCoordinateToWaypoints(e, t, n = !0) {
|
|
654
|
+
e.lng = l.convertToStdLng(e.lng, 8);
|
|
655
|
+
let s = Number.MAX_VALUE, o = 0, i = 0, r = 0;
|
|
656
|
+
for (let c = 0; c < t.length - 1; c++) {
|
|
657
|
+
const a = { lng: t[c].lng, lat: t[c].lat }, d = { lng: t[c + 1].lng, lat: t[c + 1].lat }, u = this.calculatePointToLineDistance(e, a, d);
|
|
658
|
+
s >= u && (s = u, o = c, i = this.calculateDistance(a, e, !1, 6), r = this.calculateDistance(d, e, !1, 6));
|
|
659
|
+
}
|
|
660
|
+
return i !== 0 && r !== 0 ? i < s || i === s && o === 0 ? t.unshift(e) : r < s || r === s && o === t.length - 2 ? t.push(e) : t.splice(o + 1, 0, e) : i === 0 ? n && t.splice(o, 1, e) : r === 0 && n && t.splice(o + 1, 1, e), t.map((c) => (c.lng = l.convertToStdLng(c.lng), c));
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* 生成航线(基于途经点生成大圆/横向航线,并根据是否跨180度分组)
|
|
664
|
+
* @param waypoints [{lng, lat}, {lng: lat, gcToPrevious: true}]
|
|
665
|
+
* @return [[[lng, lat], [lng, lat]]]
|
|
666
|
+
*/
|
|
667
|
+
static generateRouteAccordingToWaypoints(e) {
|
|
668
|
+
const t = [];
|
|
669
|
+
for (let n = 1; n < e.length; n++) {
|
|
670
|
+
const s = e[n - 1], o = e[n];
|
|
671
|
+
if (n === 1 && t.push(s), o.gcToPrevious) {
|
|
672
|
+
const i = this.interpolateCoordinates(s, o, 200, !1, !0, "nauticalmiles");
|
|
673
|
+
t.push(...i);
|
|
674
|
+
} else
|
|
675
|
+
t.push(o);
|
|
676
|
+
}
|
|
677
|
+
return this.divideAccordingToLng(t, !0);
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* 最近点(从route中找出距离目标点最近的点)
|
|
681
|
+
* @param coordinate 目标点 {lng, lat}
|
|
682
|
+
* @param route [[[lng, lat]]]
|
|
683
|
+
*/
|
|
684
|
+
static nearestCoordinateInRoute(e, t) {
|
|
685
|
+
const n = g.point([e.lng, e.lat]), s = [];
|
|
686
|
+
for (const c of t) {
|
|
687
|
+
const a = c.map((d) => g.point(d));
|
|
688
|
+
s.push(...a);
|
|
689
|
+
}
|
|
690
|
+
const o = g.featureCollection(s), i = g.nearestPoint(n, o), r = g.getCoord(i);
|
|
691
|
+
return { lng: r[0], lat: r[1] };
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* 计算经过方向上的最后一个waypoint
|
|
695
|
+
* @param from
|
|
696
|
+
* @param waypoints
|
|
697
|
+
*/
|
|
698
|
+
static calculatePrevWaypoint(e, t) {
|
|
699
|
+
let n = 0;
|
|
700
|
+
this.mergeCoordinateToWaypoints(e, t);
|
|
701
|
+
for (let s = 0; s < t.length - 1; s++) {
|
|
702
|
+
const o = t[s], i = t[s + 1];
|
|
703
|
+
if (this.calculateDistance(e, o) === 0) {
|
|
704
|
+
n = s;
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
if (this.calculateDistance(e, i) === 0) {
|
|
708
|
+
n = s + 1;
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return t[n === 0 ? 0 : n - 1];
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* 计算下一个距离单位的坐标及其子航线
|
|
716
|
+
* @param from 起点坐标 {lng, lat}
|
|
717
|
+
* @param distance 航行距离
|
|
718
|
+
* @param route [[[lng, lat]]]
|
|
719
|
+
* @param units
|
|
720
|
+
* @return { coordinate: {lng, lat}, route: [[[lng, lat]]]}
|
|
721
|
+
*/
|
|
722
|
+
static calculateNextCoordinateAlongRoute(e, t, n, s = "nauticalmiles") {
|
|
723
|
+
var f;
|
|
724
|
+
const o = e.speed || 12, i = [];
|
|
725
|
+
let r = [], c = !1, a = 0, d = 0, u;
|
|
726
|
+
if (t && n.length ? (i.push(e), n.forEach((p, b) => {
|
|
727
|
+
if (c)
|
|
728
|
+
r.push(p);
|
|
729
|
+
else {
|
|
730
|
+
const T = [];
|
|
731
|
+
let P;
|
|
732
|
+
for (let m = 0; m < p.length; m++)
|
|
733
|
+
if (u)
|
|
734
|
+
T.push(p[m]);
|
|
735
|
+
else {
|
|
736
|
+
P = { lng: p[m][0], lat: p[m][1] };
|
|
737
|
+
const h = this.calculateDistance(e, P, !0, 8, s);
|
|
738
|
+
if (a += h, a < t)
|
|
739
|
+
d += h, i.push(P), e = P;
|
|
740
|
+
else {
|
|
741
|
+
if (d = t, a === t)
|
|
742
|
+
u = P, T.push([u.lng, u.lat]);
|
|
743
|
+
else {
|
|
744
|
+
const S = a - t, M = this.calculateBearing(P, e);
|
|
745
|
+
u = this.calculateCoordinate(P, M, S, s), T.push([u.lng, u.lat]), T.push([P.lng, P.lat]);
|
|
746
|
+
}
|
|
747
|
+
c = !0;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
T.length && r.push(T), b === n.length - 1 && !u && (u = P);
|
|
751
|
+
}
|
|
752
|
+
})) : (r = n, u = { ...e }), u)
|
|
753
|
+
if (i.push(u), u.distanceFromPrevious = d, u.hourFromPrevious = Math.round(d / o * 1e4) / 1e4, ((f = r[0]) == null ? void 0 : f.length) > 1) {
|
|
754
|
+
const p = { lng: r[0][1][0], lat: r[0][1][1] };
|
|
755
|
+
u.bearing = this.calculateBearing(u, p);
|
|
756
|
+
} else
|
|
757
|
+
u.bearing = 0;
|
|
758
|
+
return { coordinate: u, nextRoute: r, prevRoute: i };
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* 返回最近点及其是否为垂足(最近点不是起点或终点)
|
|
762
|
+
* @param coordinate { lng, lat }
|
|
763
|
+
* @param from {lng, lat}
|
|
764
|
+
* @param to {lng, lat}
|
|
765
|
+
*/
|
|
766
|
+
static nearestCoordinateInLine(e, t, n) {
|
|
767
|
+
const s = l.convertToStdLng(e.lng, 6), o = g.point([s, e.lat]), i = l.convertToStdLng(t.lng, 6), r = l.convertToStdLng(n.lng, 6), c = g.lineString([
|
|
768
|
+
[i, t.lat],
|
|
769
|
+
[r, n.lat]
|
|
770
|
+
]), a = g.nearestPointOnLine(c, o), d = g.getCoord(a), u = l.roundPrecision(d[0], 6), f = l.roundPrecision(d[1], 6);
|
|
771
|
+
return { lng: u, lat: f, inline: !(u === i && f === t.lat) && !(u === r && f === n.lat) };
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* 将route转coordinate
|
|
775
|
+
* @param route
|
|
776
|
+
* @param distance 临近点过虑
|
|
777
|
+
*/
|
|
778
|
+
static convertRouteToCoordinates(e, t = 0) {
|
|
779
|
+
const n = [];
|
|
780
|
+
let s, o;
|
|
781
|
+
return e.forEach((i) => {
|
|
782
|
+
i.forEach((r) => {
|
|
783
|
+
const c = { lng: r[0], lat: r[1] };
|
|
784
|
+
if (!o)
|
|
785
|
+
n.push(c), o = c;
|
|
786
|
+
else if (o.bearing === void 0)
|
|
787
|
+
o.bearing = this.calculateBearing(o, c, !0);
|
|
788
|
+
else {
|
|
789
|
+
const a = this.calculateDistance(s, c, !0);
|
|
790
|
+
a && a >= t && (s.bearing = this.calculateBearing(s, c, !0), n.push(s), o = s);
|
|
791
|
+
}
|
|
792
|
+
s = c;
|
|
793
|
+
});
|
|
794
|
+
}), s && n.push(s), n;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* 抽稀(基于转向点)
|
|
798
|
+
* @param route [[lng, lat]]
|
|
799
|
+
* @param waypoints [{ lng, lat, gcToPrevious }]
|
|
800
|
+
* @param distance
|
|
801
|
+
*/
|
|
802
|
+
static simplifyRouteToCoordinates(e, t, n = 1) {
|
|
803
|
+
let s = this.convertRouteToCoordinates(e, n);
|
|
804
|
+
return s = this.simplifyGCCoordinates(s, t), s;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* 基于大圆标识抽稀
|
|
808
|
+
* @param coordinates
|
|
809
|
+
* @param waypoints
|
|
810
|
+
*/
|
|
811
|
+
static simplifyGCCoordinates(e, t) {
|
|
812
|
+
t.forEach((s) => {
|
|
813
|
+
this.mergeCoordinateToWaypoints(s, e);
|
|
814
|
+
});
|
|
815
|
+
for (let s = 1; s < t.length; s++) {
|
|
816
|
+
const o = t[s - 1], i = t[s];
|
|
817
|
+
if (i.gcToPrevious) {
|
|
818
|
+
const r = e.findIndex((a) => a.lng === o.lng && a.lat === o.lat), c = e.findIndex((a) => a.lng === i.lng && a.lat === i.lat);
|
|
819
|
+
for (let a = c - 1; a > r; a--)
|
|
820
|
+
e.splice(a, 1);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
let n = 0;
|
|
824
|
+
for (let s = 1; s < e.length; s++) {
|
|
825
|
+
const o = e[s - 1], i = e[s];
|
|
826
|
+
i.gcToPrevious ? (o.bearing = this.calculateBearing(o, i, !1), i.distanceFromPrevious = this.calculateDistance(o, i, !1)) : (o.bearing = this.calculateBearing(o, i, !0), i.distanceFromPrevious = this.calculateDistance(o, i, !0)), n = l.roundPrecision(n + i.distanceFromPrevious), i.distanceFromStart = n;
|
|
827
|
+
}
|
|
828
|
+
return e.map((s) => (s.lng = l.convertToStdLng(s.lng), s));
|
|
829
|
+
}
|
|
830
|
+
}
|
|
300
831
|
export {
|
|
301
|
-
|
|
302
|
-
|
|
832
|
+
W as LaneHelper,
|
|
833
|
+
l as LngLatHelper,
|
|
834
|
+
I as TropicalHelper
|
|
303
835
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("moment"),require("moment-timezone"),require("tz-lookup"),require("@turf/turf")):typeof define=="function"&&define.amd?define(["exports","moment","moment-timezone","tz-lookup","@turf/turf"],g):(h=typeof globalThis<"u"?globalThis:h||self,g(h["idm-plugin-rabbitmq"]={},h.moment,h["moment-timezone"],h["tz-lookup"],h["@turf/turf"]))})(this,function(h,g,j,T,O){"use strict";function w(b){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(b){for(const t in b)if(t!=="default"){const o=Object.getOwnPropertyDescriptor(b,t);Object.defineProperty(e,t,o.get?o:{enumerable:!0,get:()=>b[t]})}}return e.default=b,Object.freeze(e)}const y=w(O);class s{static guessTimeZoneOffset(e,t){const o=T(t,e),n=g().tz(o).utcOffset();return this.roundPrecision(n/60,1)}static prettyTimeZoneOffset(e){let t=Math.floor(Math.abs(e)),o=Math.round((Math.abs(e)-t)*60);return o=o>9?o:`0${o}`,t=t>9?t:`0${t}`,e>0?`+${t}:${o}`:`-${t}:${o}`}static lng2pretty(e,t=6,o="H°M′"){e=s.convertToStdLng(e,t);let n="E";e<0&&(n="W"),e=Math.abs(e),o=o.toUpperCase();let i=e*3600,r,u,c,m,a,p;r=i%3600%60,o.indexOf("S")!==-1&&(i=i-r,u=s.padNumber(r,2,2)),c=i/60%60,o.indexOf("M")!==-1&&(o.indexOf("S")!==-1?m=s.roundPrecision(c,t).toString().padStart(2,"0"):m=s.padNumber(c,2,2),i=i-c*60),a=i/3600,o.indexOf("M")!==-1?p=s.roundPrecision(a,t).toString().padStart(3,"0"):p=s.padNumber(a,3,2);const l=`${o.replace(/S+/gi,u).replace(/M+/gi,m).replace(/H+/gi,p)}${n}`;return{direction:n,degree:s.roundPrecision(a,t),minute:s.roundPrecision(c,t),second:s.roundPrecision(r,t),pretty:l}}static lat2pretty(e,t=6,o="H°M′"){e=e%180;let n="N";e<0&&(n="S"),e=Math.abs(e),o=o.toUpperCase();let i=e*3600,r,u,c,m,a,p;r=i%3600%60,o.indexOf("S")!==-1&&(i=i-r,u=s.padNumber(r,2,2)),c=i/60%60,o.indexOf("M")!==-1&&(o.indexOf("S")!==-1?m=s.roundPrecision(c,t).toString().padStart(2,"0"):m=s.padNumber(c,2,2),i=i-c*60),a=i/3600,o.indexOf("M")!==-1?p=s.roundPrecision(a,t).toString().padStart(2,"0"):p=s.padNumber(a,2,2);const l=`${o.replace(/S+/gi,u).replace(/M+/gi,m).replace(/H+/gi,p)}${n}`;return{direction:n,degree:s.roundPrecision(a,t),minute:s.roundPrecision(c,t),second:s.roundPrecision(r,t),pretty:l}}static str2Lng(e,t=6){let o;if(isNaN(e)){e=s.strReplace(e,"LNG");const n=e[e.length-1].toUpperCase();e=e.substring(0,e.length-1).trim();const i=e.split(" ").filter(c=>c!=="").map(c=>Number(c));let[r,u]=i;if(r>360&&!u){const c=this.roundPrecision(r/100,0);u=r-c*100,r=c}o=r+(u??0)/60,n==="W"&&(o=o*-1)}else o=Number(e);return s.convertToStdLng(o,t)}static str2Lat(e,t=6){let o;if(isNaN(e)){e=s.strReplace(e,"LAT");const n=e[e.length-1].toUpperCase();e=e.substring(0,e.length-1).trim();const i=e.split(" ").filter(c=>c!=="").map(c=>Number(c));let[r,u]=i;if(r>90&&!u){const c=this.roundPrecision(r/100,0);u=r-c*100,r=c}o=r+(u??0)/60,n==="S"&&(o=o*-1)}else o=Number(e);return s.roundPrecision(o,t)}static str2LngOrLat(e,t=6,o="LAT"){e=s.strReplace(e,o);const n=e[e.length-1].toUpperCase();return["N","S"].includes(n)?{lat:s.str2Lat(e,t)}:{lng:s.str2Lng(e,t)}}static convertToStdLng(e,t=4){return e>180?(e=e%360,e=e>180?e-360:e):e<-180&&(e=e%360,e=e<-180?e+360:e),s.roundPrecision(e,t)}static roundPrecision(e,t=4){if(typeof e=="number"){const o=Number("1".padEnd(t+1,"0"));return Math.round(e*o)/o}return e}static convertToMonotonicLng2(e){for(let t=1;t<e.length;t++)e[t][0]+=Math.round((e[t-1][0]-e[t][0])/360)*360;return e}static convertToMonotonicLng(e){for(let t=1;t<e.length;t++)e[t].lng+=Math.round((e[t-1].lng-e[t].lng)/360)*360;return e}static strReplace(e,t="LAT"){e=e.replace(/([0-9]+)\.([0-9]+\.[0-9]+)/g,"$1 $2").replace(/-/g," ").replace(/°/," ").replace(/'/g," ").replace(/′/g," ").replace(/"/g," ").replace(/∼/g," ").replace(/°/g," ").replace(/,/g,".").replace(/^ /g,"").replace(/ $/g,"").trim();const o=e[e.length-1].toUpperCase();if(!["N","S","E","W"].includes(o)){const n=e,i=Number(n.split(" ")[0]);if(isNaN(i))throw new Error(`invalid Lat/Lng: ${e}`);i>=90?e=`${n}E`:i<=-90?e=`${n}W`:["LAN","LNG"].includes(t==null?void 0:t.toUpperCase())?e=`${n}${i>0?"E":"W"}`:e=`${n}${i>0?"N":"S"}`}return e}static padNumber(e,t=2,o=2){const n=Math.trunc(e).toString().padStart(t,"0"),i=Math.trunc(s.roundPrecision(e-Math.trunc(e),o)*Math.pow(10,o)).toString().padStart(o,"0");return`${n}.${i}`}}class k{static convert2Geojson(e){var o;const t=y.featureCollection([]);for(const n of e){if(n.forecasts){const i=(o=n.history)==null?void 0:o[0];for(const r of n.forecasts){const u=[],c=g(r.date).utc(),m=`${n.name}-${r.model}`;if(i){const a=g(i.updated).utc(),p=y.point([i.lng,i.lat],{model:r.model,name:n.name,date:a.format(),hour:0,format:a.format("MMM-DD/HHmm[Z]"),pressure:i.pressure>1e4?s.roundPrecision(i.pressure/100,0):s.roundPrecision(i.pressure,0),wind:{kts:i.kts,spd:i.speed||i.spd},category:m,type:"forecast"});t.features.push(p),u.push(p.geometry.coordinates)}for(const a in r==null?void 0:r.hours){const p=r.hours[a];p.wind.spd=p.wind.spd||p.wind.speed;const l=c.clone().add(Number(a),"hour"),M=y.point([p.lng,p.lat],{model:r.model,name:n.name,date:l.format(),hour:Number(a),format:l.format("MMM-DD/HHmm[Z]"),pressure:p.pressure>1e4?s.roundPrecision(p.pressure/100,0):s.roundPrecision(p.pressure,0),gusts:p.gusts,wind:p.wind||{},movement:p.movement,category:m,type:"forecast"});t.features.push(M),u.push(M.geometry.coordinates)}if((u==null?void 0:u.length)>1){const a=y.lineString(s.convertToMonotonicLng2(u),{date:r.date,id:n.id||n.name,model:r.model,name:n.name,category:m,type:"forecast"});t.features.push(a)}}}if(n.history){const i=[];for(const u of n.history){const c=g(u.updated).utc(),m=y.point([u.lng,u.lat],{name:n.name,date:c.format(),format:c.format("MMM-DD/HHmm[Z]"),pressure:u.pressure>1e4?s.roundPrecision(u.pressure/100,0):s.roundPrecision(u.pressure,0),spd:u.speed||u.spd,kts:u.kts,source:u.source,level:u.type,type:"history",category:`${n.name}-history`});t.features.push(m),i.push(m.geometry.coordinates)}const r=n.history[0];if(i.length===1&&i.push(i[0]),i.length>1){const u=y.lineString(s.convertToMonotonicLng2(i),{name:n.name,type:"history",updated:r==null?void 0:r.updated,pressure:(r==null?void 0:r.pressure)>1e4?s.roundPrecision((r==null?void 0:r.pressure)/100,0):s.roundPrecision(r==null?void 0:r.pressure,0),spd:(r==null?void 0:r.speed)||(r==null?void 0:r.spd),kts:r==null?void 0:r.kts,source:r==null?void 0:r.source,level:r==null?void 0:r.type});t.features.push(u)}}}return t}static interpolate(e,t=3){var i,r,u,c;const o=(i=e==null?void 0:e.data)==null?void 0:i.features.filter(m=>m.geometry.type==="LineString"&&m.properties.type==="forecast"),n=[];for(const m of o){const a=m.properties.name,p=m.properties.model,l=g(m.properties.date).utc();let M=t*60-(l.get("hour")*60+l.get("minute"))%(t*60);const P=(r=e==null?void 0:e.data)==null?void 0:r.features.filter(f=>f.geometry.type==="Point"&&f.properties.type==="forecast"&&f.properties.category===`${a}-${p}`);let S,$=l.clone().add(M,"minute").set({minute:0,second:0,millisecond:0});for(;S=this.pickIndex(P,$),S<=P.length-1;){if(S>0){const f=P[S],d=S===0?void 0:P[S-1],N=(M/60-((u=d==null?void 0:d.properties)==null?void 0:u.hour))/(f.properties.hour-((c=d==null?void 0:d.properties)==null?void 0:c.hour)),D=this.computeNumber(d==null?void 0:d.geometry.coordinates[0],f.geometry.coordinates[0],N),z=this.computeNumber(d==null?void 0:d.geometry.coordinates[1],f.geometry.coordinates[1],N),C=y.point([D,z],{name:a,model:p,category:f==null?void 0:f.properties.category,date:$.format(),format:$.format("MMM-DD/HHmm[Z]"),gusts:this.computeNumber(d==null?void 0:d.properties.gusts,f.properties.gusts,N),hour:this.computeNumber(d==null?void 0:d.properties.hour,f.properties.hour,N),movement:this.computeNumber(d==null?void 0:d.properties.movement,f.properties.movement,N),pressure:this.computeNumber(d==null?void 0:d.properties.pressure,f.properties.pressure,N),wind:this.computeNumber(d==null?void 0:d.properties.wind,f.properties.wind,N),type:"forecast"});n.push(C)}M+=t*60,$=l.clone().add(M,"minute").set({minute:0,second:0,millisecond:0})}}return n}static pickIndex(e,t){let o=0;for(const n of e){if(g(n.properties.date).isAfter(t))return o===0?-1:o;o++}return o}static computeNumber(e,t,o){if(e)if(t){if(isNaN(e)&&isNaN(t)&&typeof e!="string"&&typeof t!="string"){const n={};for(const i in e)n[i]=this.computeNumber(e[i],t[i],o);return n}return Math.round((e+(t-e)*o)*100)/100}else return e;else return t}}h.LngLatHelper=s,h.TropicalHelper=k,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(b,N){typeof exports=="object"&&typeof module<"u"?N(exports,require("@turf/turf"),require("moment"),require("moment-timezone"),require("tz-lookup")):typeof define=="function"&&define.amd?define(["exports","@turf/turf","moment","moment-timezone","tz-lookup"],N):(b=typeof globalThis<"u"?globalThis:b||self,N(b["idm-plugin-rabbitmq"]={},b["@turf/turf"],b.moment,b["moment-timezone"],b["tz-lookup"]))})(this,function(b,N,D,k,R){"use strict";function y(M){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(M){for(const t in M)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(M,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>M[t]})}}return e.default=M,Object.freeze(e)}const g=y(N);class l{static guessTimeZoneOffset(e,t){const n=R(t,e),s=D().tz(n).utcOffset();return this.roundPrecision(s/60,1)}static prettyTimeZoneOffset(e){let t=Math.floor(Math.abs(e)),n=Math.round((Math.abs(e)-t)*60);return n=n>9?n:`0${n}`,t=t>9?t:`0${t}`,e>0?`+${t}:${n}`:`-${t}:${n}`}static lng2pretty(e,t=6,n="H°M′"){e=l.convertToStdLng(e,t);let s="E";e<0&&(s="W"),e=Math.abs(e),n=n.toUpperCase();let o=e*3600,i,r,c,u,d,a;i=o%3600%60,n.indexOf("S")!==-1&&(o=o-i,r=l.padNumber(i,2,2)),c=o/60%60,n.indexOf("M")!==-1&&(n.indexOf("S")!==-1?u=l.roundPrecision(c,t).toString().padStart(2,"0"):u=l.padNumber(c,2,2),o=o-c*60),d=o/3600,n.indexOf("M")!==-1?a=l.roundPrecision(d,t).toString().padStart(3,"0"):a=l.padNumber(d,3,2);const h=`${n.replace(/S+/gi,r).replace(/M+/gi,u).replace(/H+/gi,a)}${s}`;return{direction:s,degree:l.roundPrecision(d,t),minute:l.roundPrecision(c,t),second:l.roundPrecision(i,t),pretty:h}}static lat2pretty(e,t=6,n="H°M′"){e=e%180;let s="N";e<0&&(s="S"),e=Math.abs(e),n=n.toUpperCase();let o=e*3600,i,r,c,u,d,a;i=o%3600%60,n.indexOf("S")!==-1&&(o=o-i,r=l.padNumber(i,2,2)),c=o/60%60,n.indexOf("M")!==-1&&(n.indexOf("S")!==-1?u=l.roundPrecision(c,t).toString().padStart(2,"0"):u=l.padNumber(c,2,2),o=o-c*60),d=o/3600,n.indexOf("M")!==-1?a=l.roundPrecision(d,t).toString().padStart(2,"0"):a=l.padNumber(d,2,2);const h=`${n.replace(/S+/gi,r).replace(/M+/gi,u).replace(/H+/gi,a)}${s}`;return{direction:s,degree:l.roundPrecision(d,t),minute:l.roundPrecision(c,t),second:l.roundPrecision(i,t),pretty:h}}static str2Lng(e,t=6){let n;if(isNaN(e)){e=l.strReplace(e,"LNG");const s=e[e.length-1].toUpperCase();e=e.substring(0,e.length-1).trim();const o=e.split(" ").filter(c=>c!=="").map(c=>Number(c));let[i,r]=o;if(i>360&&!r){const c=this.roundPrecision(i/100,0);r=i-c*100,i=c}n=i+(r??0)/60,s==="W"&&(n=n*-1)}else n=Number(e);return l.convertToStdLng(n,t)}static str2Lat(e,t=6){let n;if(isNaN(e)){e=l.strReplace(e,"LAT");const s=e[e.length-1].toUpperCase();e=e.substring(0,e.length-1).trim();const o=e.split(" ").filter(c=>c!=="").map(c=>Number(c));let[i,r]=o;if(i>90&&!r){const c=this.roundPrecision(i/100,0);r=i-c*100,i=c}n=i+(r??0)/60,s==="S"&&(n=n*-1)}else n=Number(e);return l.roundPrecision(n,t)}static str2LngOrLat(e,t=6,n="LAT"){e=l.strReplace(e,n);const s=e[e.length-1].toUpperCase();return["N","S"].includes(s)?{lat:l.str2Lat(e,t)}:{lng:l.str2Lng(e,t)}}static convertToStdLng(e,t=4){return e>180?(e=e%360,e=e>180?e-360:e):e<-180&&(e=e%360,e=e<-180?e+360:e),l.roundPrecision(e,t)}static roundPrecision(e,t=4){if(typeof e=="number"){const n=Number("1".padEnd(t+1,"0"));return Math.round(e*n)/n}return e}static convertToMonotonicLng2(e){for(let t=1;t<e.length;t++)e[t][0]+=Math.round((e[t-1][0]-e[t][0])/360)*360;return e}static convertToMonotonicLng(e){for(let t=1;t<e.length;t++)e[t].lng+=Math.round((e[t-1].lng-e[t].lng)/360)*360;return e}static strReplace(e,t="LAT"){e=e.replace(/([0-9]+)\.([0-9]+\.[0-9]+)/g,"$1 $2").replace(/-/g," ").replace(/°/," ").replace(/'/g," ").replace(/′/g," ").replace(/"/g," ").replace(/∼/g," ").replace(/°/g," ").replace(/,/g,".").replace(/^ /g,"").replace(/ $/g,"").trim();const n=e[e.length-1].toUpperCase();if(!["N","S","E","W"].includes(n)){const s=e,o=Number(s.split(" ")[0]);if(isNaN(o))throw new Error(`invalid Lat/Lng: ${e}`);o>=90?e=`${s}E`:o<=-90?e=`${s}W`:["LAN","LNG"].includes(t==null?void 0:t.toUpperCase())?e=`${s}${o>0?"E":"W"}`:e=`${s}${o>0?"N":"S"}`}return e}static padNumber(e,t=2,n=2){const s=Math.trunc(e).toString().padStart(t,"0"),o=Math.trunc(l.roundPrecision(e-Math.trunc(e),n)*Math.pow(10,n)).toString().padStart(n,"0");return`${s}.${o}`}}class x{static convert2Geojson(e){var n;const t=g.featureCollection([]);for(const s of e){if(s.forecasts){const o=(n=s.history)==null?void 0:n[0];for(const i of s.forecasts){const r=[],c=D(i.date).utc(),u=`${s.name}-${i.model}`;if(o){const d=D(o.updated).utc(),a=g.point([o.lng,o.lat],{model:i.model,name:s.name,date:d.format(),hour:0,format:d.format("MMM-DD/HHmm[Z]"),pressure:o.pressure>1e4?l.roundPrecision(o.pressure/100,0):l.roundPrecision(o.pressure,0),wind:{kts:o.kts,spd:o.speed||o.spd},category:u,type:"forecast"});t.features.push(a),r.push(a.geometry.coordinates)}for(const d in i==null?void 0:i.hours){const a=i.hours[d];a.wind.spd=a.wind.spd||a.wind.speed;const h=c.clone().add(Number(d),"hour"),p=g.point([a.lng,a.lat],{model:i.model,name:s.name,date:h.format(),hour:Number(d),format:h.format("MMM-DD/HHmm[Z]"),pressure:a.pressure>1e4?l.roundPrecision(a.pressure/100,0):l.roundPrecision(a.pressure,0),gusts:a.gusts,wind:a.wind||{},movement:a.movement,category:u,type:"forecast"});t.features.push(p),r.push(p.geometry.coordinates)}if((r==null?void 0:r.length)>1){const d=g.lineString(l.convertToMonotonicLng2(r),{date:i.date,id:s.id||s.name,model:i.model,name:s.name,category:u,type:"forecast"});t.features.push(d)}}}if(s.history){const o=[];for(const r of s.history){const c=D(r.updated).utc(),u=g.point([r.lng,r.lat],{name:s.name,date:c.format(),format:c.format("MMM-DD/HHmm[Z]"),pressure:r.pressure>1e4?l.roundPrecision(r.pressure/100,0):l.roundPrecision(r.pressure,0),spd:r.speed||r.spd,kts:r.kts,source:r.source,level:r.type,type:"history",category:`${s.name}-history`});t.features.push(u),o.push(u.geometry.coordinates)}const i=s.history[0];if(o.length===1&&o.push(o[0]),o.length>1){const r=g.lineString(l.convertToMonotonicLng2(o),{name:s.name,type:"history",updated:i==null?void 0:i.updated,pressure:(i==null?void 0:i.pressure)>1e4?l.roundPrecision((i==null?void 0:i.pressure)/100,0):l.roundPrecision(i==null?void 0:i.pressure,0),spd:(i==null?void 0:i.speed)||(i==null?void 0:i.spd),kts:i==null?void 0:i.kts,source:i==null?void 0:i.source,level:i==null?void 0:i.type});t.features.push(r)}}}return t}static interpolate(e,t=3){var o,i,r,c;const n=(o=e==null?void 0:e.data)==null?void 0:o.features.filter(u=>u.geometry.type==="LineString"&&u.properties.type==="forecast"),s=[];for(const u of n){const d=u.properties.name,a=u.properties.model,h=D(u.properties.date).utc();let p=t*60-(h.get("hour")*60+h.get("minute"))%(t*60);const v=(i=e==null?void 0:e.data)==null?void 0:i.features.filter(m=>m.geometry.type==="Point"&&m.properties.type==="forecast"&&m.properties.category===`${d}-${a}`);let T,P=h.clone().add(p,"minute").set({minute:0,second:0,millisecond:0});for(;T=this.pickIndex(v,P),T<=v.length-1;){if(T>0){const m=v[T],f=T===0?void 0:v[T-1],S=(p/60-((r=f==null?void 0:f.properties)==null?void 0:r.hour))/(m.properties.hour-((c=f==null?void 0:f.properties)==null?void 0:c.hour)),C=this.computeNumber(f==null?void 0:f.geometry.coordinates[0],m.geometry.coordinates[0],S),I=this.computeNumber(f==null?void 0:f.geometry.coordinates[1],m.geometry.coordinates[1],S),W=g.point([C,I],{name:d,model:a,category:m==null?void 0:m.properties.category,date:P.format(),format:P.format("MMM-DD/HHmm[Z]"),gusts:this.computeNumber(f==null?void 0:f.properties.gusts,m.properties.gusts,S),hour:this.computeNumber(f==null?void 0:f.properties.hour,m.properties.hour,S),movement:this.computeNumber(f==null?void 0:f.properties.movement,m.properties.movement,S),pressure:this.computeNumber(f==null?void 0:f.properties.pressure,m.properties.pressure,S),wind:this.computeNumber(f==null?void 0:f.properties.wind,m.properties.wind,S),type:"forecast"});s.push(W)}p+=t*60,P=h.clone().add(p,"minute").set({minute:0,second:0,millisecond:0})}}return s}static pickIndex(e,t){let n=0;for(const s of e){if(D(s.properties.date).isAfter(t))return n===0?-1:n;n++}return n}static computeNumber(e,t,n){if(e)if(t){if(isNaN(e)&&isNaN(t)&&typeof e!="string"&&typeof t!="string"){const s={};for(const o in e)s[o]=this.computeNumber(e[o],t[o],n);return s}return Math.round((e+(t-e)*n)*100)/100}else return e;else return t}}class ${static calculateBearing(e,t,n=!0,s=4){const o=g.points([[e.lng,e.lat],[t.lng,t.lat]]);let i;return n?i=g.rhumbBearing(o.features[0],o.features[1]):i=g.bearing(o.features[0],o.features[1]),i<0&&(i+=360),l.roundPrecision(i,s)}static calculateDistance(e,t,n=!0,s=4,o="nauticalmiles"){e={...e},t={...t},e.lng=l.convertToStdLng(e.lng,s),t.lng=l.convertToStdLng(t.lng,s);const i=g.points([[e.lng,e.lat],[t.lng,t.lat]]);let r;return n?r=g.rhumbDistance(i.features[0],i.features[1],{units:o}):r=g.distance(i.features[0],i.features[1],{units:o}),l.roundPrecision(r,s)}static calculateRouteDistance(e,t=4,n="nauticalmiles"){let s=0,o;for(const i of e)for(let r=0;r<i.length-1;r++){const c={lng:i[r][0],lat:i[r][1]};r===0&&o&&(s+=this.calculateDistance(o,c,!0,t,n));const u={lng:i[r+1][0],lat:i[r+1][1]};s+=this.calculateDistance(c,u,!0,t,n),o=u}return l.roundPrecision(s,t)}static calculateCoordinate(e,t,n,s="nauticalmiles",o=!0){const i=g.point([e.lng,e.lat]);let r;o?r=g.rhumbDestination(i,n,t,{units:s}):r=g.destination(i,n,t,{units:s});const c=r.geometry.coordinates;return{lng:l.convertToStdLng(c[0],8),lat:l.roundPrecision(c[1],8)}}static interpolateCoordinates(e,t,n,s=!0,o=!0,i="nauticalmiles"){const r=[],c=this.calculateBearing(e,t,!1),u=this.calculateDistance(e,t,!1,8,i);s&&r.push({lng:e.lng,lat:e.lat});let d=0;for(;d<u;)d+=n,d<u&&r.push(this.calculateCoordinate(e,c,d,i,!1));return o&&r.push({lng:t.lng,lat:t.lat}),r}static divideAccordingToLng(e,t=!1){if((e==null?void 0:e.length)<2)return[];e=this.deduplicateCoordinates(e);let n=[];const s=[];let o,i;for(let r=0;r<e.length-1;r++){o=l.convertToStdLng(e[r].lng,8),i=l.convertToStdLng(e[r+1].lng,8),n.push([o,e[r].lat]);const c=o-i;if(Math.abs(c)>180){const u=l.convertToMonotonicLng2([[o,e[r].lat],[i,e[r+1].lat]]);let d,a;t?(d=g.lineString(u),a=g.lineString([[c>0?180:-180,89],[c>0?180:-180,-89]])):(d=g.greatCircle(u[0],u[1]),a=g.greatCircle([c>0?180:-180,89],[c>0?180:-180,-89]));const h=g.lineIntersect(d,a);let p;if(h.features.length){const v=g.getCoord(h.features[0]);p=l.roundPrecision(v[1],8)}else p=e[r].lat;c>0?(n.push([180-1e-6,p]),s.push([...n]),n=[],n.push([-(180-1e-6),p])):(n.push([-(180-1e-6),p]),s.push([...n]),n=[],n.push([180-1e-6,p]))}r===e.length-2&&n.push([i,e[r+1].lat])}return s.push(n),s}static deduplicateRoute(e){const t=[];for(const n of e){const s=n.reduce((o,i)=>(o.findIndex(r=>r[0]===i[0]&&r[1]===i[1])===-1&&o.push(i),o),[]);t.push(s)}return t}static deduplicateCoordinates(e){return e.reduce((t,n)=>(t.findIndex(s=>s.lat===n.lat&&s.lng===n.lng)===-1&&t.push(n),t),[])}static removeCoordinateFromRoute(e,t){e.lng=l.convertToStdLng(e.lng,8);for(const n of t)for(let s=n.length-1;s>=0;s--)l.roundPrecision(n[s][0],8)===e.lng&&l.roundPrecision(n[s][1],8)===l.roundPrecision(e.lat,8)&&n.splice(s,1);return t}static removeCoordinateFromWaypoints(e,t){e.lng=l.convertToStdLng(e.lng,8);for(let n=t.length-1;n>=0;n--)l.roundPrecision(t[n].lng,8)===e.lng&&l.roundPrecision(t[n].lat,8)===l.roundPrecision(e.lat,8)&&t.splice(n,1);return t}static mergeCoordinateToRoute(e,t){e.lng=l.convertToStdLng(e.lng,8);let n=Number.MAX_VALUE,s=0,o=0,i,r;return t.forEach((c,u)=>{for(let d=0;d<c.length-1;d++){const a={lng:c[d][0],lat:c[d][1]},h={lng:c[d+1][0],lat:c[d+1][1]},p=this.calculatePointToLineDistance(e,a,h);n>p&&(n=p,o=d,s=u,i=this.calculateDistance(a,e),r=this.calculateDistance(h,e))}}),i!==0&&r!==0?t[s].splice(o+1,0,[e.lng,e.lat]):i===0?t[s].splice(o,1,[e.lng,e.lat]):r===0&&t[s].splice(o+1,1,[e.lng,e.lat]),t}static mergeWaypointsToRoute(e,t){for(const n of e)t=this.mergeCoordinateToRoute(n,t);return t}static calculateRangeRoute(e,t,n){n=this.mergeWaypointsToRoute([e,t],n);const s=[];let o=0;return n.forEach(i=>{if(o===2)return;const r=[];for(const c of i){if(l.roundPrecision(t.lng,8)===l.roundPrecision(c[0],8)&&l.roundPrecision(t.lat,8)===l.roundPrecision(c[1],8)){r.push(c),o===0&&r.push([e.lng,e.lat]),o=2;break}o===1?r.push(c):l.roundPrecision(e.lng,8)===l.roundPrecision(c[0],8)&&l.roundPrecision(e.lat,8)===l.roundPrecision(c[1],8)&&(o=1,r.push(c))}r.length&&s.push(r)}),s}static calculateRangeWaypoints(e,t,n,s=[]){const o=this.convertRouteToCoordinates(n,0),i=this.mergeCoordinatesToWaypoints([e,t,...s],o),r=i.findIndex(d=>l.roundPrecision(e.lng,8)===l.roundPrecision(d.lng,8)&&l.roundPrecision(e.lat,8)===l.roundPrecision(d.lat,8)),c=i.findIndex(d=>l.roundPrecision(t.lng,8)===l.roundPrecision(d.lng,8)&&l.roundPrecision(t.lat,8)===l.roundPrecision(d.lat,8));return i.filter((d,a)=>a>=r&&a<=c)}static calculateMinDistanceToRoute(e,t){let n=Number.MAX_VALUE,s=0,o=0;return t.forEach((i,r)=>{for(let c=0;c<i.length-1;c++){const u={lng:i[c][0],lat:i[c][1]},d={lng:i[c+1][0],lat:i[c+1][1]},a=this.calculatePointToLineDistance(e,u,d);n>a&&(n=a,s=c,o=r)}}),{minDist:n,segIndex:o,minIndex:s}}static calculateSubRoute(e,t){const{segIndex:n,minIndex:s}=this.calculateMinDistanceToRoute({...e},t);e.lng=l.convertToStdLng(e.lng);const o=[];let i=!0;for(let r=n;r<t.length;r++)if(i){const c=[];c.push([e.lng,e.lat]);for(let u=s+1;u<t[r].length;u++)e.lng===t[r][u][0]&&e.lat===t[r][u][1]||c.push(t[r][u]);o.push(c),i=!1}else o.push([...t[r]]);return o}static calculateSubWaypoints(e,t){let n=Number.MAX_VALUE,s=0;for(let i=0;i<t.length-1;i++){const r=t[i],c=t[i+1];if(this.calculateDistance(e,r)===0)return t;if(this.calculateDistance(e,c)===0)return t.filter((d,a)=>a>0);const u=this.calculatePointToLineDistance(e,r,c);n>u&&(n=u,s=i)}e.lng=l.convertToStdLng(e.lng);const o=[e];for(let i=s+1;i<t.length;i++)o.push(t[i]);return o}static calculatePointToLineDistance(e,t,n,s={units:"nauticalmiles",method:"geodesic"}){e.lng=l.convertToStdLng(e.lng),t={...t},n={...n},t.lng=l.convertToStdLng(t.lng,8),n.lng=l.convertToStdLng(n.lng,8);const o=l.convertToMonotonicLng([t,n]);t=o[0],n=o[1];const i=g.lineString([[t.lng,t.lat],[n.lng,n.lat]]),r=g.pointToLineDistance(g.point([e.lng,e.lat]),i,s),c=g.pointToLineDistance(g.point([e.lng>0?e.lng-360:e.lng+360,e.lat]),i,s);return l.roundPrecision(Math.min(r,c),6)}static calculateWaypointsPropInRoute(e,t){t=this.mergeWaypointsToRoute(e,t);for(let n=0;n<e.length-1;n++){const s=e[n],o=e[n+1],i=this.calculateRangeRoute(s,o,t);n===0&&(s.distanceFromPrevious=0,s.distanceFromStart=0),o.distanceFromPrevious=this.calculateRouteDistance(i),o.distanceFromStart=l.roundPrecision((s.distanceFromStart||0)+o.distanceFromPrevious)}return e}static mergeCoordinatesToWaypoints(e,t,n=!0){for(const s of e)this.mergeCoordinateToWaypoints(s,t,n);return t}static mergeCoordinateToWaypoints(e,t,n=!0){e.lng=l.convertToStdLng(e.lng,8);let s=Number.MAX_VALUE,o=0,i=0,r=0;for(let c=0;c<t.length-1;c++){const u={lng:t[c].lng,lat:t[c].lat},d={lng:t[c+1].lng,lat:t[c+1].lat},a=this.calculatePointToLineDistance(e,u,d);s>=a&&(s=a,o=c,i=this.calculateDistance(u,e,!1,6),r=this.calculateDistance(d,e,!1,6))}return i!==0&&r!==0?i<s||i===s&&o===0?t.unshift(e):r<s||r===s&&o===t.length-2?t.push(e):t.splice(o+1,0,e):i===0?n&&t.splice(o,1,e):r===0&&n&&t.splice(o+1,1,e),t.map(c=>(c.lng=l.convertToStdLng(c.lng),c))}static generateRouteAccordingToWaypoints(e){const t=[];for(let n=1;n<e.length;n++){const s=e[n-1],o=e[n];if(n===1&&t.push(s),o.gcToPrevious){const i=this.interpolateCoordinates(s,o,200,!1,!0,"nauticalmiles");t.push(...i)}else t.push(o)}return this.divideAccordingToLng(t,!0)}static nearestCoordinateInRoute(e,t){const n=g.point([e.lng,e.lat]),s=[];for(const c of t){const u=c.map(d=>g.point(d));s.push(...u)}const o=g.featureCollection(s),i=g.nearestPoint(n,o),r=g.getCoord(i);return{lng:r[0],lat:r[1]}}static calculatePrevWaypoint(e,t){let n=0;this.mergeCoordinateToWaypoints(e,t);for(let s=0;s<t.length-1;s++){const o=t[s],i=t[s+1];if(this.calculateDistance(e,o)===0){n=s;break}if(this.calculateDistance(e,i)===0){n=s+1;break}}return t[n===0?0:n-1]}static calculateNextCoordinateAlongRoute(e,t,n,s="nauticalmiles"){var h;const o=e.speed||12,i=[];let r=[],c=!1,u=0,d=0,a;if(t&&n.length?(i.push(e),n.forEach((p,v)=>{if(c)r.push(p);else{const T=[];let P;for(let m=0;m<p.length;m++)if(a)T.push(p[m]);else{P={lng:p[m][0],lat:p[m][1]};const f=this.calculateDistance(e,P,!0,8,s);if(u+=f,u<t)d+=f,i.push(P),e=P;else{if(d=t,u===t)a=P,T.push([a.lng,a.lat]);else{const S=u-t,C=this.calculateBearing(P,e);a=this.calculateCoordinate(P,C,S,s),T.push([a.lng,a.lat]),T.push([P.lng,P.lat])}c=!0}}T.length&&r.push(T),v===n.length-1&&!a&&(a=P)}})):(r=n,a={...e}),a)if(i.push(a),a.distanceFromPrevious=d,a.hourFromPrevious=Math.round(d/o*1e4)/1e4,((h=r[0])==null?void 0:h.length)>1){const p={lng:r[0][1][0],lat:r[0][1][1]};a.bearing=this.calculateBearing(a,p)}else a.bearing=0;return{coordinate:a,nextRoute:r,prevRoute:i}}static nearestCoordinateInLine(e,t,n){const s=l.convertToStdLng(e.lng,6),o=g.point([s,e.lat]),i=l.convertToStdLng(t.lng,6),r=l.convertToStdLng(n.lng,6),c=g.lineString([[i,t.lat],[r,n.lat]]),u=g.nearestPointOnLine(c,o),d=g.getCoord(u),a=l.roundPrecision(d[0],6),h=l.roundPrecision(d[1],6);return{lng:a,lat:h,inline:!(a===i&&h===t.lat)&&!(a===r&&h===n.lat)}}static convertRouteToCoordinates(e,t=0){const n=[];let s,o;return e.forEach(i=>{i.forEach(r=>{const c={lng:r[0],lat:r[1]};if(!o)n.push(c),o=c;else if(o.bearing===void 0)o.bearing=this.calculateBearing(o,c,!0);else{const u=this.calculateDistance(s,c,!0);u&&u>=t&&(s.bearing=this.calculateBearing(s,c,!0),n.push(s),o=s)}s=c})}),s&&n.push(s),n}static simplifyRouteToCoordinates(e,t,n=1){let s=this.convertRouteToCoordinates(e,n);return s=this.simplifyGCCoordinates(s,t),s}static simplifyGCCoordinates(e,t){t.forEach(s=>{this.mergeCoordinateToWaypoints(s,e)});for(let s=1;s<t.length;s++){const o=t[s-1],i=t[s];if(i.gcToPrevious){const r=e.findIndex(u=>u.lng===o.lng&&u.lat===o.lat),c=e.findIndex(u=>u.lng===i.lng&&u.lat===i.lat);for(let u=c-1;u>r;u--)e.splice(u,1)}}let n=0;for(let s=1;s<e.length;s++){const o=e[s-1],i=e[s];i.gcToPrevious?(o.bearing=this.calculateBearing(o,i,!1),i.distanceFromPrevious=this.calculateDistance(o,i,!1)):(o.bearing=this.calculateBearing(o,i,!0),i.distanceFromPrevious=this.calculateDistance(o,i,!0)),n=l.roundPrecision(n+i.distanceFromPrevious),i.distanceFromStart=n}return e.map(s=>(s.lng=l.convertToStdLng(s.lng),s))}}b.LaneHelper=$,b.LngLatHelper=l,b.TropicalHelper=x,Object.defineProperty(b,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 坐标
|
|
3
|
+
*/
|
|
4
|
+
export interface Coordinate {
|
|
5
|
+
lng: number;
|
|
6
|
+
lat: number;
|
|
7
|
+
distanceFromPrevious?: number;
|
|
8
|
+
distanceFromStart?: number;
|
|
9
|
+
gcToPrevious?: boolean;
|
|
10
|
+
speed?: number;
|
|
11
|
+
sog?: number;
|
|
12
|
+
hourFromPrevious?: number;
|
|
13
|
+
bearing?: number;
|
|
14
|
+
important?: boolean;
|
|
15
|
+
suspend?: number;
|
|
16
|
+
velocity?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class LaneHelper {
|
|
19
|
+
/**
|
|
20
|
+
* 计算方位角
|
|
21
|
+
* @param from 坐标 {lng, lat}
|
|
22
|
+
* @param to 坐标 {lng, lat}
|
|
23
|
+
* @param rhumb true 横向方位角,false 大圆方位角
|
|
24
|
+
* @param precision
|
|
25
|
+
* @returns {number} 单位度
|
|
26
|
+
*/
|
|
27
|
+
static calculateBearing(from: Coordinate, to: Coordinate, rhumb?: boolean, precision?: number): number;
|
|
28
|
+
/**
|
|
29
|
+
* 计算两点间距离
|
|
30
|
+
* @param from 坐标 {lng, lat}
|
|
31
|
+
* @param to 坐标 {lng, lat}
|
|
32
|
+
* @param rhumb true 横向距离,false 大圆距离
|
|
33
|
+
* @param precision
|
|
34
|
+
* @param units 单位,默认 nm(海里)
|
|
35
|
+
* @returns {number}
|
|
36
|
+
*/
|
|
37
|
+
static calculateDistance(from: Coordinate, to: Coordinate, rhumb?: boolean, precision?: number, units?: string): number;
|
|
38
|
+
/**
|
|
39
|
+
* 计算航线距离
|
|
40
|
+
* @param route [[[lng, lat],[lng, lat]]]
|
|
41
|
+
* @param precision
|
|
42
|
+
* @param units
|
|
43
|
+
*/
|
|
44
|
+
static calculateRouteDistance(route: number[][][], precision?: number, units?: string): number;
|
|
45
|
+
/**
|
|
46
|
+
* 计算坐标(基于方位角和距离)
|
|
47
|
+
* @param from 坐标 {lng, lat}
|
|
48
|
+
* @param bearing 方位角,单位度
|
|
49
|
+
* @param distance 距离
|
|
50
|
+
* @param units 单位,默认 nm(海里)
|
|
51
|
+
* @param rhumb
|
|
52
|
+
*/
|
|
53
|
+
static calculateCoordinate(from: Coordinate, bearing: number, distance: number, units?: any, rhumb?: boolean): {
|
|
54
|
+
lng: number;
|
|
55
|
+
lat: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 插值大圆坐标(基于两点方位角和间距)
|
|
59
|
+
* @param from 坐标 {lng, lat}
|
|
60
|
+
* @param to 坐标 {lng, lat}
|
|
61
|
+
* @param spacing 间距
|
|
62
|
+
* @param includeHead true 包含起点 from
|
|
63
|
+
* @param includeTail true 包含终点 to
|
|
64
|
+
* @param units 单位,默认 nm(海里)
|
|
65
|
+
*/
|
|
66
|
+
static interpolateCoordinates(from: Coordinate, to: Coordinate, spacing: number, includeHead?: boolean, includeTail?: boolean, units?: string): {
|
|
67
|
+
lng: number;
|
|
68
|
+
lat: number;
|
|
69
|
+
}[];
|
|
70
|
+
/**
|
|
71
|
+
* 分组坐标(如相邻两个坐标经度差超180度,需以180为界将坐标分为两组)
|
|
72
|
+
* @param coordinates [{lng, lat}]
|
|
73
|
+
* @param rhumb
|
|
74
|
+
* @example
|
|
75
|
+
* coordinates: [{lng: 160,lat: 30}, {lng: 170, lat: 40},{lng: -170, lat: 40},{lng: -160, lat: 30}]
|
|
76
|
+
* @return [
|
|
77
|
+
* [[160, 30],[170,40]],
|
|
78
|
+
* [[-170,40],[-160,30]]
|
|
79
|
+
* ]
|
|
80
|
+
*/
|
|
81
|
+
static divideAccordingToLng(coordinates: Array<Coordinate>, rhumb?: boolean): number[][][];
|
|
82
|
+
/**
|
|
83
|
+
* 去除重复坐标
|
|
84
|
+
* @param route
|
|
85
|
+
*/
|
|
86
|
+
static deduplicateRoute(route: number[][][]): any;
|
|
87
|
+
/**
|
|
88
|
+
* 去除重新坐标
|
|
89
|
+
* @param coordinates
|
|
90
|
+
*/
|
|
91
|
+
static deduplicateCoordinates(coordinates: Array<Coordinate>): Array<Coordinate>;
|
|
92
|
+
/**
|
|
93
|
+
* 移出坐标
|
|
94
|
+
* @param coordinate {lng, lat}
|
|
95
|
+
* @param route 航线[[[lng, lat],[lng, lat]]]
|
|
96
|
+
*/
|
|
97
|
+
static removeCoordinateFromRoute(coordinate: Coordinate, route: number[][][]): number[][][];
|
|
98
|
+
/**
|
|
99
|
+
* 移出坐标
|
|
100
|
+
* @param coordinate {lng, lat}
|
|
101
|
+
* @param waypoints [{lat, lng}, {lat, lng}]
|
|
102
|
+
*/
|
|
103
|
+
static removeCoordinateFromWaypoints(coordinate: Coordinate, waypoints: Coordinate[]): Coordinate[];
|
|
104
|
+
/**
|
|
105
|
+
* 合并坐标进航线(基于坐标到线段最短距离边合并)
|
|
106
|
+
* @param coordinate 待合并的坐标 {lng, lat}
|
|
107
|
+
* @param route 航线[[[lng, lat],[lng, lat]]]
|
|
108
|
+
* @example
|
|
109
|
+
* coordinate {lng: 122, lat: 35}
|
|
110
|
+
*
|
|
111
|
+
* route: [[[120, 30], [125,40], [130, 37]], [[-150, 40], [-130, 30]]]
|
|
112
|
+
* @return
|
|
113
|
+
* [[[120, 30], [120, 35], [125,40], [130, 37]], [[-150, 40], [-130, 30]]]
|
|
114
|
+
*/
|
|
115
|
+
static mergeCoordinateToRoute(coordinate: Coordinate, route: number[][][]): number[][][];
|
|
116
|
+
/**
|
|
117
|
+
* 合并多个waypoints进航线
|
|
118
|
+
* @param waypoints [{lat, lng}, {lat, lng}]
|
|
119
|
+
* @param route 航线 [[[lng, lat],[lng, lat]]]
|
|
120
|
+
*/
|
|
121
|
+
static mergeWaypointsToRoute(waypoints: Coordinate[], route: number[][][]): number[][][];
|
|
122
|
+
/**
|
|
123
|
+
* 计算区间航线
|
|
124
|
+
* @param from {lng, lat}
|
|
125
|
+
* @param to {lng, lat}
|
|
126
|
+
* @param route [[[lng, lat]]]
|
|
127
|
+
* @return [[[lng, lat]]]
|
|
128
|
+
*/
|
|
129
|
+
static calculateRangeRoute(from: Coordinate, to: Coordinate, route: number[][][]): number[][][];
|
|
130
|
+
/**
|
|
131
|
+
* 计算from到to之间的航线
|
|
132
|
+
* @param from {lng, lat}
|
|
133
|
+
* @param to {lng, lat}
|
|
134
|
+
* @param route [[[lng, lat]]]
|
|
135
|
+
* @param waypoints
|
|
136
|
+
* @return [{lng, lat}]
|
|
137
|
+
*/
|
|
138
|
+
static calculateRangeWaypoints(from: Coordinate, to: Coordinate, route: number[][][], waypoints?: Coordinate[]): any[];
|
|
139
|
+
/**
|
|
140
|
+
* 计算坐标到航路上的最短距离
|
|
141
|
+
* @param from
|
|
142
|
+
* @param route
|
|
143
|
+
*/
|
|
144
|
+
static calculateMinDistanceToRoute(from: Coordinate, route: number[][][]): {
|
|
145
|
+
minDist: number;
|
|
146
|
+
segIndex: number;
|
|
147
|
+
minIndex: number;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* 计算子航线
|
|
151
|
+
* @param from {lng, lat} 起始位置
|
|
152
|
+
* @param route [[[lng, lat]]] 剩余航线
|
|
153
|
+
* @return [[[lng, lat]]]
|
|
154
|
+
*/
|
|
155
|
+
static calculateSubRoute(from: Coordinate, route: number[][][]): number[][][];
|
|
156
|
+
/**
|
|
157
|
+
* 计算子途经点
|
|
158
|
+
* @param from {lng, lat} 起始位置
|
|
159
|
+
* @param waypoints [{lng, lat}]
|
|
160
|
+
* @return [{lng, lat}]
|
|
161
|
+
*/
|
|
162
|
+
static calculateSubWaypoints(from: Coordinate, waypoints: Coordinate[]): Coordinate[];
|
|
163
|
+
/**
|
|
164
|
+
* 计算坐标到以(from, to)横向线上的距离
|
|
165
|
+
* @param coordinate { lng, lat }
|
|
166
|
+
* @param from { lng, lat }
|
|
167
|
+
* @param to { lng, lat }
|
|
168
|
+
* @param options
|
|
169
|
+
*/
|
|
170
|
+
static calculatePointToLineDistance(coordinate: Coordinate, from: Coordinate, to: Coordinate, options?: {
|
|
171
|
+
units: any;
|
|
172
|
+
method: any;
|
|
173
|
+
}): number;
|
|
174
|
+
/**
|
|
175
|
+
* 计算途经点的COG, Distance等属性
|
|
176
|
+
* @param waypoints
|
|
177
|
+
* @param route
|
|
178
|
+
*/
|
|
179
|
+
static calculateWaypointsPropInRoute(waypoints: Coordinate[], route: number[][][]): Coordinate[];
|
|
180
|
+
/**
|
|
181
|
+
* @param coordinates [{lng, lat}]
|
|
182
|
+
* @param waypoints [{lng, lat}]
|
|
183
|
+
* @param replace true replace the same waypoint with coordinate
|
|
184
|
+
*/
|
|
185
|
+
static mergeCoordinatesToWaypoints(coordinates: Coordinate[], waypoints: Coordinate[], replace?: boolean): Coordinate[];
|
|
186
|
+
/**
|
|
187
|
+
* 合并坐标进航路途经点
|
|
188
|
+
* @param coordinate 坐标 {lng, lat}
|
|
189
|
+
* @param waypoints 途经点 [{lng, lat}, {lng, lat}]
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* coordinate: { lng: 179, lat: 50 }
|
|
193
|
+
* waypoints: [{ lng: 160, lat: 30}, { lng: 170, lat: 40}, {lng: -170, lat: 40}, {lng: -160, lat: 30}]
|
|
194
|
+
* @param replace true replace the same waypoint with coordinate
|
|
195
|
+
* @return
|
|
196
|
+
* [{ lng: 160, lat: 30}, { lng: 170, lat: 40}, {lng: 179, lat: 50}, {lng: -170, lat: 40}, {lng: -160, lat: 30}]
|
|
197
|
+
*/
|
|
198
|
+
static mergeCoordinateToWaypoints(coordinate: Coordinate, waypoints: Coordinate[], replace?: boolean): Coordinate[];
|
|
199
|
+
/**
|
|
200
|
+
* 生成航线(基于途经点生成大圆/横向航线,并根据是否跨180度分组)
|
|
201
|
+
* @param waypoints [{lng, lat}, {lng: lat, gcToPrevious: true}]
|
|
202
|
+
* @return [[[lng, lat], [lng, lat]]]
|
|
203
|
+
*/
|
|
204
|
+
static generateRouteAccordingToWaypoints(waypoints: Coordinate[]): number[][][];
|
|
205
|
+
/**
|
|
206
|
+
* 最近点(从route中找出距离目标点最近的点)
|
|
207
|
+
* @param coordinate 目标点 {lng, lat}
|
|
208
|
+
* @param route [[[lng, lat]]]
|
|
209
|
+
*/
|
|
210
|
+
static nearestCoordinateInRoute(coordinate: Coordinate, route: number[][][]): {
|
|
211
|
+
lng: number;
|
|
212
|
+
lat: number;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* 计算经过方向上的最后一个waypoint
|
|
216
|
+
* @param from
|
|
217
|
+
* @param waypoints
|
|
218
|
+
*/
|
|
219
|
+
static calculatePrevWaypoint(from: Coordinate, waypoints: Coordinate[]): Coordinate;
|
|
220
|
+
/**
|
|
221
|
+
* 计算下一个距离单位的坐标及其子航线
|
|
222
|
+
* @param from 起点坐标 {lng, lat}
|
|
223
|
+
* @param distance 航行距离
|
|
224
|
+
* @param route [[[lng, lat]]]
|
|
225
|
+
* @param units
|
|
226
|
+
* @return { coordinate: {lng, lat}, route: [[[lng, lat]]]}
|
|
227
|
+
*/
|
|
228
|
+
static calculateNextCoordinateAlongRoute(from: Coordinate, distance: number, route: number[][][], units?: string): {
|
|
229
|
+
coordinate: Coordinate | undefined;
|
|
230
|
+
nextRoute: number[][][];
|
|
231
|
+
prevRoute: Coordinate[];
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* 返回最近点及其是否为垂足(最近点不是起点或终点)
|
|
235
|
+
* @param coordinate { lng, lat }
|
|
236
|
+
* @param from {lng, lat}
|
|
237
|
+
* @param to {lng, lat}
|
|
238
|
+
*/
|
|
239
|
+
static nearestCoordinateInLine(coordinate: Coordinate, from: Coordinate, to: Coordinate): {
|
|
240
|
+
lng: number;
|
|
241
|
+
lat: number;
|
|
242
|
+
inline: boolean;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* 将route转coordinate
|
|
246
|
+
* @param route
|
|
247
|
+
* @param distance 临近点过虑
|
|
248
|
+
*/
|
|
249
|
+
static convertRouteToCoordinates(route: number[][][], distance?: number): Coordinate[];
|
|
250
|
+
/**
|
|
251
|
+
* 抽稀(基于转向点)
|
|
252
|
+
* @param route [[lng, lat]]
|
|
253
|
+
* @param waypoints [{ lng, lat, gcToPrevious }]
|
|
254
|
+
* @param distance
|
|
255
|
+
*/
|
|
256
|
+
static simplifyRouteToCoordinates(route: number[][][], waypoints: Coordinate[], distance?: number): Coordinate[];
|
|
257
|
+
/**
|
|
258
|
+
* 基于大圆标识抽稀
|
|
259
|
+
* @param coordinates
|
|
260
|
+
* @param waypoints
|
|
261
|
+
*/
|
|
262
|
+
static simplifyGCCoordinates(coordinates: Coordinate[], waypoints: Coordinate[]): Coordinate[];
|
|
263
|
+
}
|