@idm-plugin/vessel 1.8.6 → 1.8.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.js +402 -390
- package/dist/index.umd.cjs +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,14 +2,14 @@ var ht = Object.defineProperty;
|
|
|
2
2
|
var lt = (C, e, t) => e in C ? ht(C, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : C[e] = t;
|
|
3
3
|
var G = (C, e, t) => (lt(C, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
4
|
import B from "got";
|
|
5
|
-
import
|
|
5
|
+
import rt from "@log4js-node/log4js-api";
|
|
6
6
|
import b from "moment";
|
|
7
7
|
import { LngLatHelper as J, LaneHelper as W } from "@idm-plugin/geo2";
|
|
8
8
|
import { MeteoHelper2 as ft, MeteoHelper as mt } from "@idm-plugin/meteo2";
|
|
9
9
|
import { Meteo2Assist as ct } from "@idm-plugin/meteo";
|
|
10
|
-
let
|
|
10
|
+
let v;
|
|
11
11
|
try {
|
|
12
|
-
|
|
12
|
+
v = rt.getLogger("vessel");
|
|
13
13
|
} catch {
|
|
14
14
|
} finally {
|
|
15
15
|
}
|
|
@@ -63,14 +63,14 @@ class Ct extends et {
|
|
|
63
63
|
this.clientId = t, this.clientSecret = n;
|
|
64
64
|
}
|
|
65
65
|
async authToken(t = {}) {
|
|
66
|
-
const n = "https://svc.data.myvessel.cn/ada/oauth/token",
|
|
66
|
+
const n = "https://svc.data.myvessel.cn/ada/oauth/token", r = {
|
|
67
67
|
searchParams: {
|
|
68
68
|
client_id: this.clientId,
|
|
69
69
|
client_secret: this.clientSecret,
|
|
70
70
|
grant_type: "client_credentials"
|
|
71
71
|
}
|
|
72
|
-
}, a = await B.post(n,
|
|
73
|
-
|
|
72
|
+
}, a = await B.post(n, r).json();
|
|
73
|
+
v == null || v.info("[%s] fetch access token from: %s - %j", t.requestId, n, a), a.error || (this.token = {
|
|
74
74
|
accessToken: a.access_token,
|
|
75
75
|
tokenType: a.token_type,
|
|
76
76
|
expiresIn: a.expires_in,
|
|
@@ -80,18 +80,18 @@ class Ct extends et {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
async realTimePosition(t, n = {}) {
|
|
83
|
-
var h, M,
|
|
83
|
+
var h, M, y;
|
|
84
84
|
(!this.token || b().diff(b(this.token.issuedAt), "seconds") > ((h = this.token) == null ? void 0 : h.expiresIn) - 300) && await this.authToken(n);
|
|
85
|
-
const
|
|
85
|
+
const r = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit", a = {
|
|
86
86
|
headers: {
|
|
87
|
-
Authorization: `${(M = this.token) == null ? void 0 : M.tokenType} ${(
|
|
87
|
+
Authorization: `${(M = this.token) == null ? void 0 : M.tokenType} ${(y = this.token) == null ? void 0 : y.accessToken}`
|
|
88
88
|
},
|
|
89
89
|
searchParams: { mmsi: t }
|
|
90
90
|
};
|
|
91
|
-
|
|
92
|
-
const o = await B.get(
|
|
91
|
+
v == null || v.info("[%s] fetch realtime position from: %s - %j", n.requestId, r, a);
|
|
92
|
+
const o = await B.get(r, a).json();
|
|
93
93
|
if (o.code)
|
|
94
|
-
return
|
|
94
|
+
return v == null || v.warn("[%s] fetch realtime position failed: %j", n.requestId, r, { message: o.message, status: o.status, code: o.code }), o;
|
|
95
95
|
const s = o.data;
|
|
96
96
|
for (const g in s)
|
|
97
97
|
!isNaN(s[g]) && Number(s[g]) !== 1 / 0 && (s[g] = Number(s[g]));
|
|
@@ -121,35 +121,35 @@ class Ct extends et {
|
|
|
121
121
|
utc: d.utc().format()
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
async trajectory(t, n,
|
|
124
|
+
async trajectory(t, n, r, a, o = !0, s = {}) {
|
|
125
125
|
(!this.token || b().diff(b(this.token.issuedAt), "seconds") > this.token.expiresIn - 300) && await this.authToken(s);
|
|
126
|
-
const d = await this.realTimePosition(t, s),
|
|
127
|
-
for (; h.diff(
|
|
128
|
-
await this.trajectoryIn30Day(t,
|
|
129
|
-
return await this.trajectoryIn30Day(t,
|
|
126
|
+
const d = await this.realTimePosition(t, s), i = b(n), h = b(r), M = [];
|
|
127
|
+
for (; h.diff(i, "day", !0) > 30; )
|
|
128
|
+
await this.trajectoryIn30Day(t, i, i.clone().add(30, "day"), d, a, M, s), i.add(30, "day");
|
|
129
|
+
return await this.trajectoryIn30Day(t, i, h, d, a, M, s), M;
|
|
130
130
|
}
|
|
131
|
-
async trajectoryIn30Day(t, n,
|
|
132
|
-
var
|
|
133
|
-
const
|
|
131
|
+
async trajectoryIn30Day(t, n, r, a, o, s, d = {}) {
|
|
132
|
+
var m, F, x, w, p;
|
|
133
|
+
const i = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/track", h = {
|
|
134
134
|
headers: {
|
|
135
|
-
Authorization: `${(
|
|
135
|
+
Authorization: `${(m = this.token) == null ? void 0 : m.tokenType} ${(F = this.token) == null ? void 0 : F.accessToken}`
|
|
136
136
|
},
|
|
137
137
|
json: {
|
|
138
138
|
mmsi: t,
|
|
139
139
|
startTime: n.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),
|
|
140
|
-
endTime:
|
|
140
|
+
endTime: r.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
|
-
|
|
144
|
-
const M = await B.post(
|
|
143
|
+
v == null || v.info("[%s] fetch trajectory from: %s - %j", d.requestId, i, h);
|
|
144
|
+
const M = await B.post(i, h).json();
|
|
145
145
|
if (M.code)
|
|
146
|
-
return
|
|
147
|
-
let
|
|
148
|
-
const g = b(`${(
|
|
149
|
-
return (
|
|
146
|
+
return v == null || v.warn("[%s] fetch trajectory failed: %j", d.requestId, i, { message: M.message, status: M.status, code: M.code }), M;
|
|
147
|
+
let y = -1;
|
|
148
|
+
const g = b(`${(w = (x = M.data) == null ? void 0 : x[0]) == null ? void 0 : w.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
149
|
+
return (p = M.data) == null || p.forEach((c) => {
|
|
150
150
|
for (const Y in c)
|
|
151
151
|
!isNaN(c[Y]) && Number(c[Y]) !== 1 / 0 && (c[Y] = Number(c[Y]));
|
|
152
|
-
const
|
|
152
|
+
const f = b(`${c.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00"), l = c.status, { labelCn: u, labelEn: I } = this.parseStatus(l), k = {
|
|
153
153
|
mmsi: c.mmsi,
|
|
154
154
|
imo: a == null ? void 0 : a.imo,
|
|
155
155
|
lat: c.lat,
|
|
@@ -158,17 +158,17 @@ class Ct extends et {
|
|
|
158
158
|
cog: c.cog,
|
|
159
159
|
hdg: c.hdg,
|
|
160
160
|
draught: c.draught,
|
|
161
|
-
status:
|
|
161
|
+
status: l,
|
|
162
162
|
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(c.eta) ? b(`${c.eta} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00").utc().format() : void 0,
|
|
163
163
|
destination: c.dest,
|
|
164
|
-
positionTime:
|
|
164
|
+
positionTime: f.unix(),
|
|
165
165
|
labelCn: u,
|
|
166
|
-
labelEn:
|
|
166
|
+
labelEn: I,
|
|
167
167
|
method: "trajectory",
|
|
168
168
|
vendor: "myVessel",
|
|
169
|
-
utc:
|
|
170
|
-
}, D = Math.floor(
|
|
171
|
-
D !==
|
|
169
|
+
utc: f.utc().format()
|
|
170
|
+
}, D = Math.floor(f.diff(g, "minute", !0) / (o || 1));
|
|
171
|
+
D !== y && (y = D, s.push(k));
|
|
172
172
|
}), s;
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -179,20 +179,20 @@ class Et extends et {
|
|
|
179
179
|
this.token = t;
|
|
180
180
|
}
|
|
181
181
|
async realTimePosition(t, n = {}) {
|
|
182
|
-
const
|
|
182
|
+
const r = "https://api.hifleet.com/position/position/get/token", a = {
|
|
183
183
|
searchParams: {
|
|
184
184
|
mmsi: t,
|
|
185
185
|
usertoken: this.token
|
|
186
186
|
}
|
|
187
|
-
}, o = await B.post(
|
|
188
|
-
|
|
187
|
+
}, o = await B.post(r, a).json();
|
|
188
|
+
v == null || v.info("[%s] fetch realtime position from: %s - %j", n.requestId, r, a);
|
|
189
189
|
const s = o == null ? void 0 : o.list;
|
|
190
190
|
if (!s)
|
|
191
|
-
return
|
|
191
|
+
return v == null || v.warn("[%s] fetch realtime position failed: %j", n.requestId, r, o), o;
|
|
192
192
|
for (const g in s)
|
|
193
193
|
!isNaN(s[g]) && Number(s[g]) !== 1 / 0 && (s[g] = Number(s[g]));
|
|
194
194
|
s.status = s.sp > 3 ? 0 : 1;
|
|
195
|
-
const d = s.status, { labelCn:
|
|
195
|
+
const d = s.status, { labelCn: i, labelEn: h } = this.parseStatus(d), M = b(`${s.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
196
196
|
return {
|
|
197
197
|
mmsi: s.m,
|
|
198
198
|
name: s.n,
|
|
@@ -212,14 +212,14 @@ class Et extends et {
|
|
|
212
212
|
positionTime: M.unix(),
|
|
213
213
|
utc: M.utc().format(),
|
|
214
214
|
status: d,
|
|
215
|
-
labelCn:
|
|
215
|
+
labelCn: i,
|
|
216
216
|
labelEn: h,
|
|
217
217
|
method: "position",
|
|
218
218
|
vendor: "hifleet"
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
async search(t, n = {}) {
|
|
222
|
-
let
|
|
222
|
+
let r = "https://www.hifleet.com/hifleetapi/searchVesselOL.do";
|
|
223
223
|
const a = {
|
|
224
224
|
searchParams: {
|
|
225
225
|
keyword: t
|
|
@@ -230,8 +230,8 @@ class Et extends et {
|
|
|
230
230
|
Host: "www.hifleet.com"
|
|
231
231
|
}
|
|
232
232
|
};
|
|
233
|
-
let o = await B.post(
|
|
234
|
-
|
|
233
|
+
let o = await B.post(r, a).json();
|
|
234
|
+
v == null || v.info("[%s] fetch vessel props from: %s - %j", n.requestId, r, a), o instanceof Array && (o = o[0]);
|
|
235
235
|
for (const d in o)
|
|
236
236
|
!isNaN(o[d]) && Number(o[d]) !== 1 / 0 && (o[d] = Number(o[d]));
|
|
237
237
|
const s = {
|
|
@@ -244,10 +244,10 @@ class Et extends et {
|
|
|
244
244
|
draught: o.dr,
|
|
245
245
|
type: o.t
|
|
246
246
|
};
|
|
247
|
-
return
|
|
247
|
+
return r = "https://www.hifleet.com/hifleetapi/sameShipSearch.do", o = await B.post(r, a).json(), v == null || v.info("[%s] search vessel dead weight from: %s - %j", n.requestId, r, a), o instanceof Array && (o = o[0]), o && (s.deadweight = Number(o.dwt)), s;
|
|
248
248
|
}
|
|
249
249
|
async suggest(t, n = {}) {
|
|
250
|
-
const
|
|
250
|
+
const r = "https://www.hifleet.com/hifleetapi/getShipSuggest.do", a = {
|
|
251
251
|
searchParams: {
|
|
252
252
|
q: t
|
|
253
253
|
},
|
|
@@ -256,8 +256,8 @@ class Et extends et {
|
|
|
256
256
|
Origin: "https://www.hifleet.com",
|
|
257
257
|
Host: "www.hifleet.com"
|
|
258
258
|
}
|
|
259
|
-
}, o = await B.post(
|
|
260
|
-
|
|
259
|
+
}, o = await B.post(r, a).json();
|
|
260
|
+
v == null || v.info("[%s] suggest vessel props from: %s - %j", n.requestId, r, a);
|
|
261
261
|
const s = [];
|
|
262
262
|
for (const d of o)
|
|
263
263
|
s.push({
|
|
@@ -267,37 +267,37 @@ class Et extends et {
|
|
|
267
267
|
imo: !d.imo || isNaN(d.imo) ? null : Number(d.imo),
|
|
268
268
|
score: d._score
|
|
269
269
|
});
|
|
270
|
-
return s.sort((d,
|
|
270
|
+
return s.sort((d, i) => i.score - d.score), s;
|
|
271
271
|
}
|
|
272
|
-
async trajectory(t, n,
|
|
273
|
-
var c,
|
|
272
|
+
async trajectory(t, n, r, a, o = !0, s = {}) {
|
|
273
|
+
var c, f, l;
|
|
274
274
|
const d = await this.realTimePosition(t, s);
|
|
275
|
-
let
|
|
276
|
-
const h = b(
|
|
275
|
+
let i = b(n);
|
|
276
|
+
const h = b(r), M = b();
|
|
277
277
|
if (o) {
|
|
278
|
-
let u = h.diff(
|
|
279
|
-
u < 0 ?
|
|
278
|
+
let u = h.diff(i, "d", !0);
|
|
279
|
+
u < 0 ? i = h.clone().subtract(40, "d") : u < 30 ? i.subtract(10, "d") : u < 60 ? i.subtract(5, "d") : i = h.clone().subtract(80, "d"), u = M.diff(h, "d", !0), h.add(u > 10 ? 240 : u * 24, "h");
|
|
280
280
|
}
|
|
281
|
-
const
|
|
281
|
+
const y = {
|
|
282
282
|
searchParams: {
|
|
283
283
|
endtime: h.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
284
|
-
starttime:
|
|
284
|
+
starttime: i.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
285
285
|
mmsi: t,
|
|
286
286
|
usertoken: this.token
|
|
287
287
|
}
|
|
288
|
-
}, g = "https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",
|
|
289
|
-
|
|
290
|
-
let
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
let
|
|
294
|
-
const
|
|
295
|
-
for (const u of
|
|
288
|
+
}, g = "https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token", m = await B.get(g, y).json();
|
|
289
|
+
v == null || v.info("[%s] fetch trajectory from: %s - %j", s.requestId, g, y);
|
|
290
|
+
let F;
|
|
291
|
+
m && (F = ((f = (c = m.ships) == null ? void 0 : c.offors) == null ? void 0 : f.ship) || [], F.length || v == null || v.warn("[%s] fetch trajectory failed: %j", s.requestId, m));
|
|
292
|
+
const x = [];
|
|
293
|
+
let w = -1;
|
|
294
|
+
const p = b(`${(l = F == null ? void 0 : F[0]) == null ? void 0 : l.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
295
|
+
for (const u of F) {
|
|
296
296
|
for (const P in u)
|
|
297
297
|
!isNaN(u[P]) && Number(u[P]) !== 1 / 0 && (u[P] = Number(u[P]));
|
|
298
|
-
const
|
|
298
|
+
const I = b(`${u.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
299
299
|
u.status = u.sp > 4 ? 0 : 1;
|
|
300
|
-
const { labelEn:
|
|
300
|
+
const { labelEn: k, labelCn: D } = this.parseStatus(u.status), Y = {
|
|
301
301
|
mmsi: u.m,
|
|
302
302
|
name: u.n,
|
|
303
303
|
imo: d == null ? void 0 : d.imo,
|
|
@@ -307,17 +307,17 @@ class Et extends et {
|
|
|
307
307
|
sog: u.sp,
|
|
308
308
|
cog: u.co,
|
|
309
309
|
hdg: u.hdg,
|
|
310
|
-
positionTime:
|
|
311
|
-
utc:
|
|
310
|
+
positionTime: I.unix(),
|
|
311
|
+
utc: I.utc().format(),
|
|
312
312
|
status: u.status,
|
|
313
313
|
labelCn: D,
|
|
314
|
-
labelEn:
|
|
314
|
+
labelEn: k,
|
|
315
315
|
method: "trajectory",
|
|
316
316
|
vendor: "hifleet"
|
|
317
|
-
}, E = Math.floor(
|
|
318
|
-
E !==
|
|
317
|
+
}, E = Math.floor(I.diff(p, "minute", !0) / (a || 1));
|
|
318
|
+
E !== w && (w = E, x.push(Y));
|
|
319
319
|
}
|
|
320
|
-
return
|
|
320
|
+
return x;
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
class Nt extends et {
|
|
@@ -327,19 +327,19 @@ class Nt extends et {
|
|
|
327
327
|
this.token = t;
|
|
328
328
|
}
|
|
329
329
|
async realTimePosition(t, n = {}) {
|
|
330
|
-
const
|
|
330
|
+
const r = {
|
|
331
331
|
searchParams: {
|
|
332
332
|
id: t,
|
|
333
333
|
k: this.token,
|
|
334
334
|
enc: 1
|
|
335
335
|
}
|
|
336
|
-
}, a = "https://api.shipxy.com/apicall/GetSingleShip", o = await B.get(a,
|
|
337
|
-
if (
|
|
336
|
+
}, a = "https://api.shipxy.com/apicall/GetSingleShip", o = await B.get(a, r).json();
|
|
337
|
+
if (v == null || v.info("[%s] fetch realtime position from: %s - %j", n.requestId, a, r), (o == null ? void 0 : o.status) !== 0)
|
|
338
338
|
return o;
|
|
339
339
|
const s = o.data[0];
|
|
340
|
-
for (const
|
|
341
|
-
!isNaN(s[
|
|
342
|
-
const { labelCn: d, labelEn:
|
|
340
|
+
for (const y in s)
|
|
341
|
+
!isNaN(s[y]) && Number(s[y]) !== 1 / 0 && (s[y] = Number(s[y]));
|
|
342
|
+
const { labelCn: d, labelEn: i } = await this.parseStatus(s.navistat), h = b.unix(s.lasttime);
|
|
343
343
|
return {
|
|
344
344
|
mmsi: s.ShipID,
|
|
345
345
|
name: s.name,
|
|
@@ -357,44 +357,44 @@ class Nt extends et {
|
|
|
357
357
|
positionTime: s.lasttime,
|
|
358
358
|
utc: h.utc().format(),
|
|
359
359
|
status: s.navistat,
|
|
360
|
-
labelEn:
|
|
360
|
+
labelEn: i,
|
|
361
361
|
labelCn: d,
|
|
362
362
|
method: "position",
|
|
363
363
|
vendor: "shipxy"
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
|
-
async trajectory(t, n,
|
|
367
|
-
var
|
|
368
|
-
const d = await this.realTimePosition(t, s),
|
|
366
|
+
async trajectory(t, n, r, a, o = !0, s = {}) {
|
|
367
|
+
var p;
|
|
368
|
+
const d = await this.realTimePosition(t, s), i = b(n), h = b(r), M = "https://api.shipxy.com/apicall/GetShipTrack", y = {
|
|
369
369
|
searchParams: {
|
|
370
370
|
id: t,
|
|
371
371
|
k: this.token,
|
|
372
372
|
enc: 1,
|
|
373
373
|
cut: 0,
|
|
374
|
-
btm:
|
|
374
|
+
btm: i.unix(),
|
|
375
375
|
etm: h.unix()
|
|
376
376
|
}
|
|
377
|
-
}, g = await B.get(M,
|
|
378
|
-
if (
|
|
377
|
+
}, g = await B.get(M, y).json();
|
|
378
|
+
if (v == null || v.info("[%s] fetch trajectory from: %s - %j", s.requestId, M, y), (g == null ? void 0 : g.status) !== 0)
|
|
379
379
|
return g;
|
|
380
|
-
const
|
|
381
|
-
let
|
|
382
|
-
for (const c of
|
|
383
|
-
const
|
|
380
|
+
const m = g == null ? void 0 : g.points, F = [], x = b.unix((p = m[0]) == null ? void 0 : p.utc);
|
|
381
|
+
let w = -1;
|
|
382
|
+
for (const c of m) {
|
|
383
|
+
const f = b.unix(c.utc), l = {
|
|
384
384
|
imo: d == null ? void 0 : d.imo,
|
|
385
385
|
mmsi: t,
|
|
386
386
|
sog: Math.round(c.sog * 3600 / 1e3 / 1852 * 100) / 100,
|
|
387
387
|
cog: Math.round(c.cog / 100 * 100) / 100,
|
|
388
388
|
lat: Math.round(c.lat / 1e6 * 1e5) / 1e5,
|
|
389
389
|
lng: Math.round(c.lon / 1e6 * 1e5) / 1e5,
|
|
390
|
-
positionTime:
|
|
391
|
-
utc:
|
|
390
|
+
positionTime: f.unix(),
|
|
391
|
+
utc: f.utc().format(),
|
|
392
392
|
method: "trajectory",
|
|
393
393
|
vendor: "shipxy"
|
|
394
|
-
}, u = Math.floor(
|
|
395
|
-
u !==
|
|
394
|
+
}, u = Math.floor(f.diff(x, "minute", !0) / (a || 1));
|
|
395
|
+
u !== w && (w = u, F.push(l));
|
|
396
396
|
}
|
|
397
|
-
return
|
|
397
|
+
return F;
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
class Tt extends et {
|
|
@@ -404,30 +404,30 @@ class Tt extends et {
|
|
|
404
404
|
this.token = t;
|
|
405
405
|
}
|
|
406
406
|
async getShipId(t, n = {}) {
|
|
407
|
-
const
|
|
407
|
+
const r = {
|
|
408
408
|
headers: {
|
|
409
409
|
appKey: this.token
|
|
410
410
|
},
|
|
411
411
|
json: {
|
|
412
412
|
mmsiList: t
|
|
413
413
|
}
|
|
414
|
-
}, a = "https://api3.myships.com/sp/ships/getShipIdByMMSI", o = await B.post(a,
|
|
415
|
-
return
|
|
414
|
+
}, a = "https://api3.myships.com/sp/ships/getShipIdByMMSI", o = await B.post(a, r).json();
|
|
415
|
+
return v == null || v.info("[%s] fetch ship id from: %s - %j", n.requestId, a, r), o.code !== "0" ? o : o.data[0].shipId;
|
|
416
416
|
}
|
|
417
417
|
async getShipInfo(t, n = {}) {
|
|
418
|
-
const
|
|
418
|
+
const r = {
|
|
419
419
|
headers: {
|
|
420
420
|
appKey: this.token
|
|
421
421
|
},
|
|
422
422
|
json: {
|
|
423
423
|
shipId: t
|
|
424
424
|
}
|
|
425
|
-
}, a = "https://api3.myships.com/sp/ships/aissta", o = await B.post(a,
|
|
426
|
-
if (
|
|
425
|
+
}, a = "https://api3.myships.com/sp/ships/aissta", o = await B.post(a, r).json();
|
|
426
|
+
if (v == null || v.info("[%s] fetch ship info from: %s - %j", n.requestId, a, r), o.code !== "0")
|
|
427
427
|
return o;
|
|
428
428
|
const s = o.data;
|
|
429
429
|
let d = s.imo;
|
|
430
|
-
return t === "407170" && (d = "9198379",
|
|
430
|
+
return t === "407170" && (d = "9198379", v == null || v.warn("[%s] ship(%s) imo error: %s, should be %s", n.requestId, t, s.imo, d)), {
|
|
431
431
|
mmsi: s.mmsi,
|
|
432
432
|
name: s.shipnameEn,
|
|
433
433
|
imo: d,
|
|
@@ -438,45 +438,45 @@ class Tt extends et {
|
|
|
438
438
|
};
|
|
439
439
|
}
|
|
440
440
|
async realTimePosition(t, n = {}) {
|
|
441
|
-
const
|
|
441
|
+
const r = await this.getShipId(t, n), a = await this.getShipInfo(r, n), o = {
|
|
442
442
|
headers: {
|
|
443
443
|
appKey: this.token
|
|
444
444
|
},
|
|
445
445
|
json: {
|
|
446
|
-
shipId:
|
|
446
|
+
shipId: r
|
|
447
447
|
}
|
|
448
448
|
}, s = "https://api3.myships.com/sp/ships/position/latest", d = await B.post(s, o).json();
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
for (const
|
|
452
|
-
!isNaN(
|
|
453
|
-
const { labelCn: h, labelEn: M } = await this.parseStatus(
|
|
449
|
+
v == null || v.info("[%s] fetch realtime position from: %s - %j", n.requestId, s, o);
|
|
450
|
+
const i = d.data[0];
|
|
451
|
+
for (const m in i)
|
|
452
|
+
!isNaN(i[m]) && Number(i[m]) !== 1 / 0 && (i[m] = Number(i[m]));
|
|
453
|
+
const { labelCn: h, labelEn: M } = await this.parseStatus(i.aisNavStatus), y = b.unix(i.posTime);
|
|
454
454
|
return {
|
|
455
455
|
...a,
|
|
456
456
|
mmsi: t,
|
|
457
|
-
lat: Math.round(
|
|
458
|
-
lng: Math.round(
|
|
459
|
-
sog: Math.round(
|
|
460
|
-
cog: Math.round(
|
|
461
|
-
hdg: Math.round(
|
|
462
|
-
rot: Math.round(
|
|
463
|
-
positionTime:
|
|
464
|
-
utc:
|
|
465
|
-
status:
|
|
457
|
+
lat: Math.round(i.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
458
|
+
lng: Math.round(i.lon / 1e4 / 60 * 1e5) / 1e5,
|
|
459
|
+
sog: Math.round(i.sog / 10 * 100) / 100,
|
|
460
|
+
cog: Math.round(i.cog / 10 * 100) / 100,
|
|
461
|
+
hdg: Math.round(i.heading * 100) / 100,
|
|
462
|
+
rot: Math.round(i.rot * 100) / 100,
|
|
463
|
+
positionTime: i.posTime,
|
|
464
|
+
utc: y.utc().format(),
|
|
465
|
+
status: i.aisNavStatus,
|
|
466
466
|
labelEn: M,
|
|
467
467
|
labelCn: h,
|
|
468
468
|
method: "position",
|
|
469
469
|
vendor: "myship"
|
|
470
470
|
};
|
|
471
471
|
}
|
|
472
|
-
async trajectory(t, n,
|
|
473
|
-
const d = b(n),
|
|
474
|
-
for (;
|
|
475
|
-
await this.trajectoryIn30Day(h, d.unix(), d.add(30, "day").unix(), M, t, a,
|
|
476
|
-
return await this.trajectoryIn30Day(h, d.unix(),
|
|
472
|
+
async trajectory(t, n, r, a, o = !0, s = {}) {
|
|
473
|
+
const d = b(n), i = b(r), h = await this.getShipId(t), M = await this.getShipInfo(h), y = [];
|
|
474
|
+
for (; i.diff(d, "day", !0) > 30; )
|
|
475
|
+
await this.trajectoryIn30Day(h, d.unix(), d.add(30, "day").unix(), M, t, a, y);
|
|
476
|
+
return await this.trajectoryIn30Day(h, d.unix(), i.unix(), M, t, a, y), y;
|
|
477
477
|
}
|
|
478
|
-
async trajectoryIn30Day(t, n,
|
|
479
|
-
var
|
|
478
|
+
async trajectoryIn30Day(t, n, r, a, o, s, d, i = {}) {
|
|
479
|
+
var x;
|
|
480
480
|
const h = {
|
|
481
481
|
headers: {
|
|
482
482
|
appKey: this.token
|
|
@@ -484,39 +484,39 @@ class Tt extends et {
|
|
|
484
484
|
json: {
|
|
485
485
|
shipId: t,
|
|
486
486
|
startTime: n,
|
|
487
|
-
endTime:
|
|
487
|
+
endTime: r
|
|
488
488
|
}
|
|
489
|
-
}, M = "https://api3.myships.com/sp/ships/position/history",
|
|
490
|
-
if (
|
|
491
|
-
return
|
|
492
|
-
const g =
|
|
493
|
-
for (const
|
|
494
|
-
!isNaN(g[
|
|
495
|
-
const
|
|
496
|
-
let
|
|
497
|
-
for (const
|
|
498
|
-
const
|
|
489
|
+
}, M = "https://api3.myships.com/sp/ships/position/history", y = await B.post(M, h).json();
|
|
490
|
+
if (v == null || v.info("[%s] fetch trajectory from: %s - %j", i.requestId, M, h), y.code !== "0")
|
|
491
|
+
return v == null || v.warn("[%s] invoke myship trajectory failed: %j", i.requestId, y), y;
|
|
492
|
+
const g = y.data;
|
|
493
|
+
for (const w in g)
|
|
494
|
+
!isNaN(g[w]) && Number(g[w]) !== 1 / 0 && (g[w] = Number(g[w]));
|
|
495
|
+
const m = b.unix((x = g[0]) == null ? void 0 : x.posTime);
|
|
496
|
+
let F = -1;
|
|
497
|
+
for (const w of g) {
|
|
498
|
+
const p = b.unix(w.posTime), c = {
|
|
499
499
|
imo: a == null ? void 0 : a.imo,
|
|
500
500
|
mmsi: o,
|
|
501
|
-
lat: Math.round(
|
|
502
|
-
lng: Math.round(
|
|
503
|
-
sog: Math.round(
|
|
504
|
-
cog: Math.round(
|
|
505
|
-
hdg: Math.round(
|
|
506
|
-
rot: Math.round(
|
|
507
|
-
positionTime:
|
|
508
|
-
utc:
|
|
501
|
+
lat: Math.round(w.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
502
|
+
lng: Math.round(w.lon / 1e4 / 60 * 1e5) / 1e5,
|
|
503
|
+
sog: Math.round(w.sog / 10 * 100) / 100,
|
|
504
|
+
cog: Math.round(w.cog / 10 * 100) / 100,
|
|
505
|
+
hdg: Math.round(w.heading * 100) / 100,
|
|
506
|
+
rot: Math.round(w.rot * 100) / 100,
|
|
507
|
+
positionTime: p.unix(),
|
|
508
|
+
utc: p.utc().format(),
|
|
509
509
|
method: "trajectory",
|
|
510
510
|
vendor: "myship"
|
|
511
|
-
},
|
|
512
|
-
|
|
511
|
+
}, f = Math.floor(p.diff(m, "minute", !0) / (s || 1));
|
|
512
|
+
f !== F && (F = f, d.push(c));
|
|
513
513
|
}
|
|
514
514
|
return d;
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
let _;
|
|
518
518
|
try {
|
|
519
|
-
_ =
|
|
519
|
+
_ = rt.getLogger("vessel");
|
|
520
520
|
} catch {
|
|
521
521
|
} finally {
|
|
522
522
|
}
|
|
@@ -531,20 +531,20 @@ class Mt {
|
|
|
531
531
|
* @param options
|
|
532
532
|
*/
|
|
533
533
|
parsePrinciple(e, t = {}) {
|
|
534
|
-
var s, d,
|
|
534
|
+
var s, d, i;
|
|
535
535
|
_ == null || _.info("[%s] parse rule: %s", t.requestId, e);
|
|
536
|
-
const n = new RegExp("(?<=\\[)(.+)(?=])", "g"),
|
|
536
|
+
const n = new RegExp("(?<=\\[)(.+)(?=])", "g"), r = e.match(n) ? (s = e.match(n)) == null ? void 0 : s[0] : void 0, a = r == null ? void 0 : r.split(";");
|
|
537
537
|
if (!a)
|
|
538
538
|
return;
|
|
539
539
|
const o = {};
|
|
540
540
|
for (let h = 0; h < (a == null ? void 0 : a.length); h++) {
|
|
541
|
-
const M = (
|
|
541
|
+
const M = (i = (d = a[h].match(n)) == null ? void 0 : d[0]) == null ? void 0 : i.split("],");
|
|
542
542
|
if (h === 0 && !M)
|
|
543
543
|
o.scope = a[0];
|
|
544
544
|
else if (M)
|
|
545
|
-
for (let
|
|
546
|
-
const
|
|
547
|
-
|
|
545
|
+
for (let y = 0, g = M.length; y < g; y++) {
|
|
546
|
+
const m = this.parseRule(M[y]);
|
|
547
|
+
m && (o[m.level] ? m.key ? o[m.level][m == null ? void 0 : m.key] = m : o[m.level] = m : m.key ? o[m.level] = { [m == null ? void 0 : m.key]: m } : o[m.level] = m);
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
return o;
|
|
@@ -558,7 +558,7 @@ class Mt {
|
|
|
558
558
|
parseRule(e, t = {}) {
|
|
559
559
|
var o;
|
|
560
560
|
_ == null || _.info("[%s] parse rule: %s", t.requestId, e), e = e.startsWith("[") ? e : `[${e}`, e = e.endsWith("]") ? e : `${e}]`;
|
|
561
|
-
const n = new RegExp("(?<=\\[)(.+?)(?=])", "g"),
|
|
561
|
+
const n = new RegExp("(?<=\\[)(.+?)(?=])", "g"), r = (o = e == null ? void 0 : e.match(n)) == null ? void 0 : o[0], a = r == null ? void 0 : r.split(",");
|
|
562
562
|
if (a)
|
|
563
563
|
return {
|
|
564
564
|
operator: a[0],
|
|
@@ -575,20 +575,20 @@ class Mt {
|
|
|
575
575
|
* @param options
|
|
576
576
|
*/
|
|
577
577
|
checkWeather(e, t, n = {}) {
|
|
578
|
-
var
|
|
579
|
-
let
|
|
580
|
-
const d = Math.round(((
|
|
578
|
+
var m, F, x, w, p, c, f, l, u, I, k, D, Y, E, P;
|
|
579
|
+
let r = 0, a = 0, o = 0, s = 0;
|
|
580
|
+
const d = Math.round(((F = (m = t == null ? void 0 : t.SEVERE) == null ? void 0 : m.sigWave) == null ? void 0 : F.number) * 1.6 * 100) / 100, i = (w = (x = t == null ? void 0 : t.SEVERE) == null ? void 0 : x.sigWave) == null ? void 0 : w.number, h = (c = (p = t == null ? void 0 : t.HEAVY) == null ? void 0 : p.sigWave) == null ? void 0 : c.number, M = Math.round((((l = (f = t == null ? void 0 : t.SEVERE) == null ? void 0 : f.wind) == null ? void 0 : l.number) + 2) * 100) / 100, y = (I = (u = t == null ? void 0 : t.SEVERE) == null ? void 0 : u.wind) == null ? void 0 : I.number, g = (D = (k = t == null ? void 0 : t.HEAVY) == null ? void 0 : k.wind) == null ? void 0 : D.number;
|
|
581
581
|
for (let T = 0; T < (e == null ? void 0 : e.length); T++) {
|
|
582
582
|
const N = e[T], A = (E = (Y = N == null ? void 0 : N.meteo) == null ? void 0 : Y.wave) == null ? void 0 : E.sig, R = (P = N == null ? void 0 : N.meteo) == null ? void 0 : P.wind, K = T ? b(N.eta).diff(b(e[T - 1].eta), "hour", !0) : 0;
|
|
583
|
-
s = K > s ? K : s, _ == null || _.info("[%s] check sig.wave: %j", n.requestId, { ...A, dgThd4Wv: d, svThd4Wv:
|
|
583
|
+
s = K > s ? K : s, _ == null || _.info("[%s] check sig.wave: %j", n.requestId, { ...A, dgThd4Wv: d, svThd4Wv: i, hvThd4Wv: h }), (A == null ? void 0 : A.height) >= d ? N.isDangerous = !0 : (A == null ? void 0 : A.height) >= i ? N.isSevere = !0 : (A == null ? void 0 : A.height) >= h && (N.isHeavy = !0), _ == null || _.info("[%s] check wind: %j", n.requestId, { ...R, dgThd4Wd: M, svThd4Wd: y, hvThd4Wd: g }), (R == null ? void 0 : R.scale) >= M ? (N.isDangerous = !0, delete N.isSevere, delete N.isHeavy) : (R == null ? void 0 : R.scale) > y ? (N.isDangerous || (N.isSevere = !0), delete N.isHeavy) : (R == null ? void 0 : R.scale) === g && !N.isDangerous && !N.isSevere && (N.isHeavy = !0), r += N.isDangerous ? K : 0, a += N.isSevere ? K : 0, o += N.isHeavy ? K : 0;
|
|
584
584
|
}
|
|
585
|
-
return
|
|
585
|
+
return r = Math.round(r * 100) / 100, a = Math.round(a * 100) / 100, o = Math.round(o * 100) / 100, s = Math.round(s), { sample: e, dangerous: r, severe: a, heavy: o, step: s < 3 ? 3 : s, wind: { dgThd4Wd: M, svThd4Wd: y, hvThd4Wd: g }, sig: { dgThd4Wv: d, svThd4Wv: i, hvThd4Wv: h } };
|
|
586
586
|
}
|
|
587
587
|
}
|
|
588
588
|
const Dt = new Mt();
|
|
589
|
-
let
|
|
589
|
+
let S;
|
|
590
590
|
try {
|
|
591
|
-
|
|
591
|
+
S = rt.getLogger("vessel");
|
|
592
592
|
} catch {
|
|
593
593
|
} finally {
|
|
594
594
|
}
|
|
@@ -607,8 +607,8 @@ class O {
|
|
|
607
607
|
* @param draught 吃水 m
|
|
608
608
|
* @return [0.55, 0.85]
|
|
609
609
|
*/
|
|
610
|
-
static blockCoefficient(e, t, n,
|
|
611
|
-
let a = Math.round(e / (t * n *
|
|
610
|
+
static blockCoefficient(e, t, n, r) {
|
|
611
|
+
let a = Math.round(e / (t * n * r) * 100) / 100;
|
|
612
612
|
a = a < 0.55 ? 0.55 : a > 0.85 ? 0.85 : a;
|
|
613
613
|
const o = [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85], s = o.map((d) => Math.abs(d - a));
|
|
614
614
|
return o[s.indexOf(Math.min(...s))];
|
|
@@ -625,8 +625,8 @@ class O {
|
|
|
625
625
|
* @return [0.05, 0.30]
|
|
626
626
|
*/
|
|
627
627
|
static froudeNumber(e, t, n = 9.8) {
|
|
628
|
-
let
|
|
629
|
-
return
|
|
628
|
+
let r = Math.round(Math.sqrt(e * e / (n * t)) * 100) / 100;
|
|
629
|
+
return r = r < 0.05 ? 0.05 : r > 0.3 ? 0.3 : r, r;
|
|
630
630
|
}
|
|
631
631
|
/**
|
|
632
632
|
* 失速修正系數
|
|
@@ -636,7 +636,7 @@ class O {
|
|
|
636
636
|
* @private
|
|
637
637
|
*/
|
|
638
638
|
static amendFactor(e, t, n) {
|
|
639
|
-
const
|
|
639
|
+
const r = {
|
|
640
640
|
0.55: [1.7, -1.4, -7.4],
|
|
641
641
|
0.6: [2.2, -2.5, -9.7],
|
|
642
642
|
0.65: [2.6, -3.7, -11.6],
|
|
@@ -654,7 +654,7 @@ class O {
|
|
|
654
654
|
0.8: [3, -16.3, -21.6],
|
|
655
655
|
0.85: [3.4, -20.9, 31.8]
|
|
656
656
|
}[e];
|
|
657
|
-
return n === "Laden" && (o =
|
|
657
|
+
return n === "Laden" && (o = r[e]), o[0] + o[1] * t + o[2] * Math.pow(t, 2);
|
|
658
658
|
}
|
|
659
659
|
/**
|
|
660
660
|
* 失速方向因子
|
|
@@ -682,10 +682,10 @@ class O {
|
|
|
682
682
|
* @param bn
|
|
683
683
|
* @private
|
|
684
684
|
*/
|
|
685
|
-
static vesselTagFactor(e, t, n,
|
|
686
|
-
|
|
685
|
+
static vesselTagFactor(e, t, n, r = 0) {
|
|
686
|
+
r = r > 6 ? r - 0.9 * (r - 6) : r;
|
|
687
687
|
let a;
|
|
688
|
-
return n === "container" ? a = 0.7 *
|
|
688
|
+
return n === "container" ? a = 0.7 * r + Math.pow(r, 6.5) / (22 * Math.pow(e, 2 / 3)) : t === "Ballast" ? a = 0.7 * r + Math.pow(r, 6.5) / (2.7 * Math.pow(e, 2 / 3)) : a = 0.5 * r + Math.pow(r, 6.5) / (2.7 * Math.pow(e, 2 / 3)), a;
|
|
689
689
|
}
|
|
690
690
|
/**
|
|
691
691
|
* 浪高影响因子
|
|
@@ -705,11 +705,11 @@ class O {
|
|
|
705
705
|
* @param bearing 方位角
|
|
706
706
|
* @private
|
|
707
707
|
*/
|
|
708
|
-
static assembleProperties(e, t, n,
|
|
709
|
-
var
|
|
710
|
-
const a = e.lbp ?? e.length ?? e.lengthOverall ?? 198.9642, o = e.draught ?? 8, s = e.breadthMoulded ?? e.breadth ?? e.breadthExtreme ?? 32.4572, d = e.deadweight ?? 67035.7773,
|
|
708
|
+
static assembleProperties(e, t, n, r) {
|
|
709
|
+
var y;
|
|
710
|
+
const a = e.lbp ?? e.length ?? e.lengthOverall ?? 198.9642, o = e.draught ?? 8, s = e.breadthMoulded ?? e.breadth ?? e.breadthExtreme ?? 32.4572, d = e.deadweight ?? 67035.7773, i = ((y = e == null ? void 0 : e.type) == null ? void 0 : y.toLowerCase()) || "common";
|
|
711
711
|
return {
|
|
712
|
-
tag:
|
|
712
|
+
tag: i.indexOf("container") > -1 ? "container" : i.indexOf("tugs") > -1 ? "tugs" : "common",
|
|
713
713
|
lbp: a,
|
|
714
714
|
loadCondition: t,
|
|
715
715
|
draught: o,
|
|
@@ -719,7 +719,7 @@ class O {
|
|
|
719
719
|
displacement: Math.round((d / 1.025 + o * s * a * 0.7) * 1e4) / 1e4,
|
|
720
720
|
// 换算为m/s
|
|
721
721
|
speed: Math.round((n ?? 14.1382) * 1852 / 3600 * 1e4) / 1e4,
|
|
722
|
-
bearing:
|
|
722
|
+
bearing: r || 90
|
|
723
723
|
};
|
|
724
724
|
}
|
|
725
725
|
/**
|
|
@@ -732,37 +732,37 @@ class O {
|
|
|
732
732
|
* @param useMeteo true 启用气象分析
|
|
733
733
|
* @param useRouteParam true 启用设置速度
|
|
734
734
|
*/
|
|
735
|
-
static async speedLoseAt(e, t, n,
|
|
736
|
-
let
|
|
735
|
+
static async speedLoseAt(e, t, n, r = "", a = 2, o = !0, s = !1, d = {}) {
|
|
736
|
+
let i;
|
|
737
737
|
if (t.velocity && s && (e.speed = J.roundPrecision(t.velocity * 1852 / 3600, 6)), o) {
|
|
738
738
|
let h;
|
|
739
739
|
if (d.meteo2)
|
|
740
740
|
try {
|
|
741
|
-
const
|
|
742
|
-
h = ct.toLegacy(
|
|
743
|
-
} catch (
|
|
744
|
-
|
|
741
|
+
const m = await gt.spotForecast(t.lat, t.lng, n.utc().format(), !1, !1, !0, d), [F] = ct.pickHourly(m, n);
|
|
742
|
+
h = ct.toLegacy(F);
|
|
743
|
+
} catch (m) {
|
|
744
|
+
S.warn("[%s] meteo2 spot(%j) forecast failed: %s", d.requestId, { ...t, eta: n.utc().format() }, m);
|
|
745
745
|
}
|
|
746
746
|
else
|
|
747
|
-
h = await mt.queryPointFactor(t.lng, t.lat, n.valueOf(), "wind,wave,current,watertemp",
|
|
748
|
-
const M = O.weatherFactor(e, h),
|
|
749
|
-
|
|
747
|
+
h = await mt.queryPointFactor(t.lng, t.lat, n.valueOf(), "wind,wave,current,watertemp", r, d);
|
|
748
|
+
const M = O.weatherFactor(e, h), y = O.currentFactor(e.bearing, h == null ? void 0 : h.current, a), g = Math.round((e.speed * 1.943844 + M + y) * 100) / 100;
|
|
749
|
+
i = {
|
|
750
750
|
meteo: { ...h },
|
|
751
751
|
wxFactor: M,
|
|
752
|
-
cFactor:
|
|
752
|
+
cFactor: y,
|
|
753
753
|
speed: t.velocity && s ? t.velocity : g < 0 ? 1 : g,
|
|
754
754
|
eta: n.utc().format(),
|
|
755
755
|
etd: n.utc().format()
|
|
756
756
|
};
|
|
757
757
|
} else
|
|
758
|
-
|
|
758
|
+
i = {
|
|
759
759
|
wxFactor: 0,
|
|
760
760
|
cFactor: 0,
|
|
761
761
|
speed: t.velocity && s ? t.velocity : Math.round((e.speed * 1.943844 + 0 + 0) * 100) / 100,
|
|
762
762
|
eta: n.utc().format(),
|
|
763
763
|
etd: n.utc().format()
|
|
764
764
|
};
|
|
765
|
-
return delete t.meteo, delete t.wxFactor, delete t.cFactor, delete t.speed, delete t.etd, { ...
|
|
765
|
+
return delete t.meteo, delete t.wxFactor, delete t.cFactor, delete t.speed, delete t.etd, { ...i, ...t };
|
|
766
766
|
}
|
|
767
767
|
/**
|
|
768
768
|
* 基于步长计算失速样本
|
|
@@ -777,53 +777,53 @@ class O {
|
|
|
777
777
|
* @param useRouteParam true 启用航线上设置的参数 { suspend: 停留时长(小时), velocity: 速度(kts)}
|
|
778
778
|
* @private
|
|
779
779
|
*/
|
|
780
|
-
static async speedLoseInHoursStep(e, t, n,
|
|
780
|
+
static async speedLoseInHoursStep(e, t, n, r, a, o, s = "", d = !0, i = !1, h = {}) {
|
|
781
781
|
t.utc();
|
|
782
|
-
const M = t.clone().add(14, "days"),
|
|
783
|
-
let
|
|
784
|
-
for (let
|
|
785
|
-
let c = o[
|
|
786
|
-
c.distanceFromStart = Math.round((a +
|
|
787
|
-
const
|
|
788
|
-
if (e.bearing = W.calculateBearing(c,
|
|
782
|
+
const M = t.clone().add(14, "days"), y = [], g = [];
|
|
783
|
+
let m = 0, F = 0, x, w;
|
|
784
|
+
for (let p = 0; p < o.length - 1; p++) {
|
|
785
|
+
let c = o[p];
|
|
786
|
+
c.distanceFromStart = Math.round((a + F) * 1e4) / 1e4;
|
|
787
|
+
const f = o[p + 1];
|
|
788
|
+
if (e.bearing = W.calculateBearing(c, f, !f.gcToPrevious), c.bearing = e.bearing, c.suspend && i) {
|
|
789
789
|
c.eta = c.eta || t.utc().format(), c.elapsed = c.elapsed ?? 0;
|
|
790
|
-
const
|
|
791
|
-
if (
|
|
792
|
-
|
|
790
|
+
const I = c.suspend - c.elapsed;
|
|
791
|
+
if (r - m > I)
|
|
792
|
+
r = r - m - I, t.add(I, "hour"), c.elapsed = c.suspend;
|
|
793
793
|
else {
|
|
794
|
-
const
|
|
795
|
-
c.elapsed +=
|
|
794
|
+
const k = r - m;
|
|
795
|
+
c.elapsed += k, t.add(k, "hour"), r = 0;
|
|
796
796
|
}
|
|
797
|
-
if (
|
|
798
|
-
return c.distanceFromPrevious =
|
|
797
|
+
if (S == null || S.info(`[%s] suspend ${c.elapsed} hours at %j, and remain ${r} hours need to go...`, h.requestId, c), r === 0)
|
|
798
|
+
return c.distanceFromPrevious = F, { etd: t, from: w || c, to: c, next: o.filter((k) => k), wps: y, days: g };
|
|
799
799
|
} else
|
|
800
800
|
c.suspend = 0;
|
|
801
|
-
d = t.isAfter(M) ? !1 : d, c = await O.speedLoseAt(e, c, t, s, 0, d,
|
|
802
|
-
const
|
|
803
|
-
let u = Math.round(
|
|
804
|
-
if (
|
|
805
|
-
if (
|
|
806
|
-
`[%s] go to %j from %j with ${
|
|
801
|
+
d = t.isAfter(M) ? !1 : d, c = await O.speedLoseAt(e, c, t, s, 0, d, i, h), w = w || c, c.important && y.push(c), t.isSameOrAfter(n) && (g.push(c), n.add(24, "hour"));
|
|
802
|
+
const l = W.calculateDistance(c, f, !f.gcToPrevious);
|
|
803
|
+
let u = Math.round(l / w.speed * 1e5) / 1e5;
|
|
804
|
+
if (m + u < r) {
|
|
805
|
+
if (m += u, t.add(u, "hour"), delete o[p], S == null || S.debug(
|
|
806
|
+
`[%s] go to %j from %j with ${l}nm, and cost ${u} hours`,
|
|
807
807
|
h.requestId,
|
|
808
|
-
{ lat:
|
|
809
|
-
{ lat:
|
|
810
|
-
),
|
|
811
|
-
|
|
808
|
+
{ lat: f.lat, lng: f.lng },
|
|
809
|
+
{ lat: w.lat, lng: w.lng, etd: w.etd }
|
|
810
|
+
), F += l, o.filter((I) => I).length <= 1) {
|
|
811
|
+
x = f, x.eta = t.utc().format(), x.distanceFromPrevious = l, x.distanceFromStart = Math.round((a + F) * 1e4) / 1e4, y.push(x), delete o[p + 1];
|
|
812
812
|
break;
|
|
813
813
|
}
|
|
814
814
|
} else {
|
|
815
|
-
u =
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
`[%s] go to %j from %j with ${
|
|
815
|
+
u = r - m, t.add(u, "hour");
|
|
816
|
+
const I = J.roundPrecision(w.speed * u, 5);
|
|
817
|
+
x = W.calculateCoordinate(c, e.bearing, I, "nauticalmiles", !f.gcToPrevious), x.eta = t.utc().format(), o[p] = x, S == null || S.debug(
|
|
818
|
+
`[%s] go to %j from %j with ${I}nm, and cost ${u} hours`,
|
|
819
819
|
h.requestId,
|
|
820
|
-
{ lat:
|
|
820
|
+
{ lat: x.lat, lng: x.lng },
|
|
821
821
|
{ lat: c.lat, lng: c.lng, etd: c.etd }
|
|
822
|
-
),
|
|
822
|
+
), F += I, x.distanceFromPrevious = Math.round(F * 1e4) / 1e4, x.distanceFromStart = Math.round((a + F) * 1e4) / 1e4;
|
|
823
823
|
break;
|
|
824
824
|
}
|
|
825
825
|
}
|
|
826
|
-
return { etd: t, from:
|
|
826
|
+
return { etd: t, from: w, to: x, next: o.filter((p) => p), wps: y, days: g };
|
|
827
827
|
}
|
|
828
828
|
/**
|
|
829
829
|
* 洋流影响因子
|
|
@@ -832,10 +832,10 @@ class O {
|
|
|
832
832
|
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
833
833
|
*/
|
|
834
834
|
static currentFactor(e, t, n = 0) {
|
|
835
|
-
const
|
|
836
|
-
if (Math.abs(
|
|
835
|
+
const r = (e - (t == null ? void 0 : t.degree) || 0) / 180 * Math.PI;
|
|
836
|
+
if (Math.abs(r) === Math.PI / 2)
|
|
837
837
|
return 0;
|
|
838
|
-
let a = ((t == null ? void 0 : t.kts) || 0) * Math.cos(
|
|
838
|
+
let a = ((t == null ? void 0 : t.kts) || 0) * Math.cos(r);
|
|
839
839
|
return n & 2 ? a = Math.ceil(a * 100) / 100 : n & 1 ? a = Math.floor(a * 100) / 100 : a = Math.round(a * 100) / 100, Math.abs(a) > 5 ? 0 : a;
|
|
840
840
|
}
|
|
841
841
|
/**
|
|
@@ -844,16 +844,16 @@ class O {
|
|
|
844
844
|
* @param wwc 气象要素
|
|
845
845
|
*/
|
|
846
846
|
static weatherFactor(e, t) {
|
|
847
|
-
var M,
|
|
848
|
-
|
|
849
|
-
const n = O.blockCoefficient(e.displacement, e.lbp, e.breadthMoulded, e.draught),
|
|
847
|
+
var M, y, g, m, F, x, w;
|
|
848
|
+
S == null || S.debug("calculate weather factor via: %j", { ...e, ...t });
|
|
849
|
+
const n = O.blockCoefficient(e.displacement, e.lbp, e.breadthMoulded, e.draught), r = O.froudeNumber(e.speed, e.lbp), a = O.amendFactor(n, r, e.loadCondition);
|
|
850
850
|
let o = Math.abs(e.bearing % 360 - (((M = t == null ? void 0 : t.wind) == null ? void 0 : M.degree) % 360 || 0));
|
|
851
851
|
o = o > 180 ? 360 - o : o;
|
|
852
|
-
const s = O.directionFactor(o, (
|
|
853
|
-
let
|
|
854
|
-
|
|
855
|
-
const h = O.waveHeightFactor(((
|
|
856
|
-
return
|
|
852
|
+
const s = O.directionFactor(o, (y = t == null ? void 0 : t.wind) == null ? void 0 : y.scale), d = O.vesselTagFactor(e.displacement, e.loadCondition, e.tag, (g = t == null ? void 0 : t.wind) == null ? void 0 : g.scale);
|
|
853
|
+
let i = s * a * d / 100 * e.speed;
|
|
854
|
+
i = Math.round(i * 1.943844 * 1e4) / 1e4 * -1, e.tag === "tugs" && Math.abs(i) > 1 && (i = i / (Math.abs(Math.round(i)) + 1)), S == null || S.debug("wind wx factor = %d", i), o = Math.abs(e.bearing % 360 - (((F = (m = t == null ? void 0 : t.wave) == null ? void 0 : m.sig) == null ? void 0 : F.degree) % 360 || 0));
|
|
855
|
+
const h = O.waveHeightFactor(((w = (x = t == null ? void 0 : t.wave) == null ? void 0 : x.sig) == null ? void 0 : w.height) ?? 1, o);
|
|
856
|
+
return S == null || S.debug("wave wx factor = %d", h), i = i * 0.4 + h, S == null || S.debug("weather factor = %d", i), i = Math.abs(i) > 4 ? 4 * (Math.abs(i) / i) + Math.abs(i) / i * (Math.abs(i) - 4) * 0.1 : i, Math.round((i || 0) * 100) / 100;
|
|
857
857
|
}
|
|
858
858
|
/**
|
|
859
859
|
* 全程失速分析(走完航程)
|
|
@@ -867,79 +867,79 @@ class O {
|
|
|
867
867
|
* @param useMeteo true 启用气象分析
|
|
868
868
|
* @param useRouteParam
|
|
869
869
|
*/
|
|
870
|
-
static async analyseInstant(e, t, n,
|
|
870
|
+
static async analyseInstant(e, t, n, r, a, o = "", s = 0, d = !0, i = !1, h = {}) {
|
|
871
871
|
var z, U, Q, X, Z, $;
|
|
872
872
|
const M = b().valueOf();
|
|
873
873
|
e.lng = J.convertToStdLng(e.lng);
|
|
874
|
-
const { route:
|
|
875
|
-
if (((z =
|
|
874
|
+
const { route: y, waypoints: g } = a.points, m = W.calculateSubRoute(e, y);
|
|
875
|
+
if (((z = m[0]) == null ? void 0 : z.length) <= 1)
|
|
876
876
|
return;
|
|
877
|
-
const { v0:
|
|
877
|
+
const { v0: F, label: x } = e.sog ? {
|
|
878
878
|
v0: e.sog,
|
|
879
879
|
label: "Other"
|
|
880
880
|
/* Instruct */
|
|
881
881
|
} : {
|
|
882
|
-
v0:
|
|
882
|
+
v0: r.speed,
|
|
883
883
|
label: "CP"
|
|
884
884
|
/* Cp */
|
|
885
|
-
},
|
|
886
|
-
|
|
885
|
+
}, w = O.assembleProperties(n, r.loadCondition, F, 0), p = g.length ? W.calculateSubWaypoints(e, g) : [];
|
|
886
|
+
p.forEach((q) => q.important = !0);
|
|
887
887
|
const c = {
|
|
888
888
|
from: { ...e },
|
|
889
|
-
route:
|
|
890
|
-
waypoints:
|
|
891
|
-
v0:
|
|
892
|
-
label:
|
|
893
|
-
},
|
|
889
|
+
route: m,
|
|
890
|
+
waypoints: p,
|
|
891
|
+
v0: F,
|
|
892
|
+
label: x
|
|
893
|
+
}, f = {
|
|
894
894
|
hours: [],
|
|
895
895
|
days: [],
|
|
896
896
|
wps: []
|
|
897
897
|
};
|
|
898
|
-
s || (W.calculateRouteDistance(
|
|
899
|
-
let
|
|
898
|
+
s || (W.calculateRouteDistance(m) / r.speed <= 72 ? s = 3 : s = 6);
|
|
899
|
+
let l = W.simplifyRouteToCoordinates(m, p, 0), u = 0, I = 0, k = 0, D = 0;
|
|
900
900
|
t = b(t).utc();
|
|
901
901
|
const Y = t.clone();
|
|
902
|
-
for (;
|
|
902
|
+
for (; l.length > 0; ) {
|
|
903
903
|
const q = s - t.hour() % s, V = Math.ceil(t.clone().add(q, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4, j = await O.speedLoseInHoursStep(
|
|
904
|
-
|
|
904
|
+
w,
|
|
905
905
|
t,
|
|
906
906
|
Y,
|
|
907
907
|
V,
|
|
908
908
|
u,
|
|
909
|
-
|
|
909
|
+
l,
|
|
910
910
|
o,
|
|
911
911
|
d,
|
|
912
|
-
|
|
912
|
+
i,
|
|
913
913
|
h
|
|
914
914
|
);
|
|
915
|
-
(U = j.from) != null && U.speed && (
|
|
915
|
+
(U = j.from) != null && U.speed && (f.hours.push(j.from), f.wps.push(...j.wps), f.days.push(...j.days)), l = j == null ? void 0 : j.next, l.length || f.hours.push(j == null ? void 0 : j.to), u += Math.round((((Q = j == null ? void 0 : j.to) == null ? void 0 : Q.distanceFromPrevious) ?? 0) * 1e4) / 1e4;
|
|
916
916
|
}
|
|
917
|
-
const E =
|
|
917
|
+
const E = f.hours;
|
|
918
918
|
for (let q = 0; q < E.length - 1; q++) {
|
|
919
919
|
const V = b(E[q + 1].eta).diff(E[q].etd, "hour", !0) || 1;
|
|
920
|
-
|
|
920
|
+
I += (E[q].wxFactor || 0) * V, k += (E[q].cFactor || 0) * V, D += V;
|
|
921
921
|
}
|
|
922
|
-
(X =
|
|
922
|
+
(X = f.wps) == null || X.forEach((q, V) => {
|
|
923
923
|
q.positionTime = b.utc(q.etd || q.eta).unix();
|
|
924
|
-
const j =
|
|
924
|
+
const j = f.wps[V - 1];
|
|
925
925
|
if (j) {
|
|
926
926
|
const L = q.distanceFromStart - j.distanceFromStart, H = b(q.eta || q.etd).diff(b(j.etd || j.eta), "h", !0);
|
|
927
927
|
q.avgSpd = Math.round(L / H * 100) / 100;
|
|
928
928
|
const nt = W.calculateBearing(j, q);
|
|
929
929
|
j.bearing = nt;
|
|
930
930
|
}
|
|
931
|
-
}),
|
|
932
|
-
const P =
|
|
933
|
-
c.distance = Math.round(T.distanceFromStart * 1e4) / 1e4, c.etd = b(P.eta).utc().format(), c.eta = b(T.eta).utc().format(), c.wxFactor = Math.round(
|
|
934
|
-
const { distanceInECA: N, hoursInECA: A, totalDgoConsInECA: R, eca: K } = await this.calculateECA(c,
|
|
931
|
+
}), f.wps = (Z = f.wps) == null ? void 0 : Z.reduce((q, V) => (q.some((j) => Math.round(j.positionTime / 60) === Math.round(V.positionTime / 60)) || q.push(V), q), []), c.sample = f;
|
|
932
|
+
const P = f.hours.at(0), T = f.hours.at(-1);
|
|
933
|
+
c.distance = Math.round(T.distanceFromStart * 1e4) / 1e4, c.etd = b(P.eta).utc().format(), c.eta = b(T.eta).utc().format(), c.wxFactor = Math.round(I / D * 1e4) / 1e4, c.cFactor = Math.round(k / D * 1e4) / 1e4, c.avgSpeed = Math.round(T.distanceFromStart / D * 1e4) / 1e4, c.totalHrs = Math.round(D * 1e4) / 1e4;
|
|
934
|
+
const { distanceInECA: N, hoursInECA: A, totalDgoConsInECA: R, eca: K } = await this.calculateECA(c, r, h), st = J.roundPrecision(r.fo / 24 * (D - A), 3), at = J.roundPrecision(r.dgo / 24 * D, 3);
|
|
935
935
|
c.extend = {
|
|
936
936
|
eca: K,
|
|
937
937
|
distanceInECA: N,
|
|
938
938
|
hoursInECA: A,
|
|
939
939
|
totalDgoConsInECA: R
|
|
940
940
|
}, c.totalFoCons = st, c.totalDgoCons = at;
|
|
941
|
-
const tt = b().valueOf() - M, ot = (($ =
|
|
942
|
-
return
|
|
941
|
+
const tt = b().valueOf() - M, ot = (($ = f == null ? void 0 : f.hours) == null ? void 0 : $.length) || 1;
|
|
942
|
+
return S == null || S.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms", h == null ? void 0 : h.requestId, tt, ot, Math.round(tt / ot * 1e3) / 1e3), c;
|
|
943
943
|
}
|
|
944
944
|
/**
|
|
945
945
|
* 分段失速分析(最多走hours 小时)
|
|
@@ -954,11 +954,11 @@ class O {
|
|
|
954
954
|
* @param useMeteo true 启用气象分析
|
|
955
955
|
* @param useRouteParam
|
|
956
956
|
*/
|
|
957
|
-
static async analyseInstantWithThreshed(e, t, n,
|
|
957
|
+
static async analyseInstantWithThreshed(e, t, n, r, a, o, s, d = "", i = 3, h = !0, M = !1, y = {}) {
|
|
958
958
|
var Q, X, Z, $, q, V;
|
|
959
959
|
const g = b().valueOf();
|
|
960
960
|
e.lng = J.convertToStdLng(e.lng);
|
|
961
|
-
const { v0:
|
|
961
|
+
const { v0: m, label: F } = e.sog ? {
|
|
962
962
|
v0: e.sog,
|
|
963
963
|
label: "Other"
|
|
964
964
|
/* Instruct */
|
|
@@ -966,13 +966,13 @@ class O {
|
|
|
966
966
|
v0: a.speed,
|
|
967
967
|
label: "CP"
|
|
968
968
|
/* Cp */
|
|
969
|
-
},
|
|
970
|
-
if (((Q =
|
|
969
|
+
}, x = O.assembleProperties(r, a.loadCondition, m, 0), w = W.calculateSubRoute(e, o);
|
|
970
|
+
if (((Q = w[0]) == null ? void 0 : Q.length) <= 1)
|
|
971
971
|
return;
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
let c = W.simplifyRouteToCoordinates(
|
|
975
|
-
const
|
|
972
|
+
const p = s.length ? W.calculateSubWaypoints(e, s) : [];
|
|
973
|
+
p.forEach((j) => j.important = !0);
|
|
974
|
+
let c = W.simplifyRouteToCoordinates(w, p, 0), f = 0, l = 0, u = 0, I = 0;
|
|
975
|
+
const k = {
|
|
976
976
|
hours: [],
|
|
977
977
|
wps: [],
|
|
978
978
|
days: []
|
|
@@ -980,15 +980,15 @@ class O {
|
|
|
980
980
|
t = b(t).utc();
|
|
981
981
|
const D = t.clone();
|
|
982
982
|
for (; c.length > 0; ) {
|
|
983
|
-
const j =
|
|
983
|
+
const j = i - t.hour() % i;
|
|
984
984
|
let L = Math.ceil(t.clone().add(j, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4;
|
|
985
985
|
L = t.clone().add(L, "h").isSameOrAfter(n) ? n.diff(t, "h", !0) * 1e4 / 1e4 : L;
|
|
986
|
-
const H = await O.speedLoseInHoursStep(
|
|
987
|
-
if ((X = H.from) != null && X.speed && (
|
|
986
|
+
const H = await O.speedLoseInHoursStep(x, t, D, L, f, c, d, h, M, y);
|
|
987
|
+
if ((X = H.from) != null && X.speed && (k.hours.push(H.from), H != null && H.wps && k.wps.push(...H.wps), k.days.push(...H.days)), c = H == null ? void 0 : H.next, c.length || k.hours.push(H == null ? void 0 : H.to), f += Math.round((((Z = H == null ? void 0 : H.to) == null ? void 0 : Z.distanceFromPrevious) ?? 0) * 1e4) / 1e4, !L)
|
|
988
988
|
break;
|
|
989
989
|
}
|
|
990
|
-
|
|
991
|
-
const H =
|
|
990
|
+
k.wps = ($ = k.wps) == null ? void 0 : $.reduce((j, L) => (j.some((H) => Math.round(b(H.etd).unix() / 60) === Math.round(b(L.etd).unix() / 60)) || j.push(L), j), []), (q = k.wps) == null || q.forEach((j, L) => {
|
|
991
|
+
const H = k.wps[L - 1];
|
|
992
992
|
if (H) {
|
|
993
993
|
const nt = j.distanceFromStart - H.distanceFromStart, dt = b(j.eta || j.etd).diff(b(H.etd || H.eta), "h", !0);
|
|
994
994
|
j.avgSpd = Math.round(nt / dt * 100) / 100;
|
|
@@ -996,36 +996,36 @@ class O {
|
|
|
996
996
|
H.bearing = ut;
|
|
997
997
|
}
|
|
998
998
|
});
|
|
999
|
-
const Y =
|
|
999
|
+
const Y = k.hours;
|
|
1000
1000
|
for (let j = 0; j < Y.length - 1; j++) {
|
|
1001
1001
|
const L = b(Y[j + 1].eta).diff(Y[j].etd, "hour", !0);
|
|
1002
|
-
|
|
1002
|
+
l += Y[j].wxFactor * L, u += Y[j].cFactor * L, I += L;
|
|
1003
1003
|
}
|
|
1004
|
-
const E =
|
|
1005
|
-
sample:
|
|
1004
|
+
const E = k.hours.at(0), P = k.hours.at(-1), T = await W.calculateRangeRoute(E, P, w), N = await W.calculateRangeWaypoints(E, P, w, p), A = {
|
|
1005
|
+
sample: k,
|
|
1006
1006
|
distance: Math.round(((P == null ? void 0 : P.distanceFromStart) || 0) * 1e4) / 1e4,
|
|
1007
1007
|
// 注意,可能会在first节点Drift,所有采用eta做为初始出发时间
|
|
1008
1008
|
etd: b(E.eta).utc().format(),
|
|
1009
1009
|
eta: b(P == null ? void 0 : P.eta).utc().format(),
|
|
1010
|
-
wxFactor: Math.round(
|
|
1011
|
-
cFactor: Math.round(u /
|
|
1012
|
-
avgSpeed: Math.round(((P == null ? void 0 : P.distanceFromStart) || 0) /
|
|
1013
|
-
totalHrs: Math.round(
|
|
1010
|
+
wxFactor: Math.round(l / I * 1e4) / 1e4,
|
|
1011
|
+
cFactor: Math.round(u / I * 1e4) / 1e4,
|
|
1012
|
+
avgSpeed: Math.round(((P == null ? void 0 : P.distanceFromStart) || 0) / I * 1e4) / 1e4,
|
|
1013
|
+
totalHrs: Math.round(I * 1e4) / 1e4,
|
|
1014
1014
|
from: E,
|
|
1015
1015
|
to: P,
|
|
1016
1016
|
route: T,
|
|
1017
1017
|
waypoints: N,
|
|
1018
|
-
v0:
|
|
1019
|
-
label:
|
|
1020
|
-
}, { distanceInECA: R, hoursInECA: K, totalDgoConsInECA: st, eca: at } = await this.calculateECA(A, a,
|
|
1018
|
+
v0: m,
|
|
1019
|
+
label: F
|
|
1020
|
+
}, { distanceInECA: R, hoursInECA: K, totalDgoConsInECA: st, eca: at } = await this.calculateECA(A, a, y), it = J.roundPrecision(a.fo / 24 * (I - K), 3), tt = J.roundPrecision(a.dgo / 24 * I, 3);
|
|
1021
1021
|
A.extend = {
|
|
1022
1022
|
eca: at,
|
|
1023
1023
|
distanceInECA: R,
|
|
1024
1024
|
hoursInECA: K,
|
|
1025
1025
|
totalDgoConsInECA: st
|
|
1026
|
-
}, A.totalDgoCons = tt, A.totalFoCons =
|
|
1027
|
-
const z = b().valueOf() - g, U = ((V =
|
|
1028
|
-
return
|
|
1026
|
+
}, A.totalDgoCons = tt, A.totalFoCons = it;
|
|
1027
|
+
const z = b().valueOf() - g, U = ((V = k == null ? void 0 : k.hours) == null ? void 0 : V.length) || 1;
|
|
1028
|
+
return S == null || S.debug("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms", y == null ? void 0 : y.requestId, z, U, Math.round(z / U * 1e3) / 1e3), A;
|
|
1029
1029
|
}
|
|
1030
1030
|
/**
|
|
1031
1031
|
* 在指定航线条件下,基于多CP,动态计算最优成本(租金+油费)方案
|
|
@@ -1042,34 +1042,34 @@ class O {
|
|
|
1042
1042
|
* @param lane 基础航线(重要转向点)
|
|
1043
1043
|
* @param options
|
|
1044
1044
|
*/
|
|
1045
|
-
static async analyseCost(e, t, n,
|
|
1046
|
-
var
|
|
1045
|
+
static async analyseCost(e, t, n, r, a = {}) {
|
|
1046
|
+
var w, p;
|
|
1047
1047
|
const o = b().valueOf(), s = [];
|
|
1048
1048
|
a.meteo2 = a.meteo2 || !0, e.speedStep = e.speedStep || 3, e.alterStep = e.alterStep ?? 1;
|
|
1049
|
-
const d = W.calculateRouteDistance(
|
|
1050
|
-
let
|
|
1049
|
+
const d = W.calculateRouteDistance(r.route);
|
|
1050
|
+
let i = 0;
|
|
1051
1051
|
n.forEach((c) => {
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
}),
|
|
1055
|
-
const h = b.utc(e.etd).add(
|
|
1052
|
+
const f = Math.ceil(d / c.speed / 24);
|
|
1053
|
+
i = i < f ? f : i;
|
|
1054
|
+
}), i = i * 1.3;
|
|
1055
|
+
const h = b.utc(e.etd).add(i ?? 14, "day");
|
|
1056
1056
|
let M = 1;
|
|
1057
1057
|
for (const c of n) {
|
|
1058
|
-
const
|
|
1058
|
+
const f = JSON.parse(JSON.stringify(r.route)), l = JSON.parse(JSON.stringify(r.waypoints)), u = await O.analyseInstantWithThreshed(
|
|
1059
1059
|
{ lat: e.lat, lng: e.lng },
|
|
1060
1060
|
e.etd,
|
|
1061
1061
|
h,
|
|
1062
1062
|
t,
|
|
1063
1063
|
c,
|
|
1064
|
-
|
|
1065
|
-
|
|
1064
|
+
f,
|
|
1065
|
+
l,
|
|
1066
1066
|
e.meteoVendor,
|
|
1067
1067
|
e.speedStep,
|
|
1068
1068
|
e.useMeteo,
|
|
1069
1069
|
e.useRouteParam,
|
|
1070
1070
|
a
|
|
1071
1071
|
);
|
|
1072
|
-
u && (await O.calculateCost(u, c, e, a), s.push(u),
|
|
1072
|
+
u && (await O.calculateCost(u, c, e, a), s.push(u), S == null || S.info("[%s][L%d-%d] analyse from %s to %s cost: %j", a.requestId, 1, M, e.etd, h.format(), {
|
|
1073
1073
|
cost: u.cost.total,
|
|
1074
1074
|
hire: u.cost.hire,
|
|
1075
1075
|
bunker: u.cost.bunker,
|
|
@@ -1078,23 +1078,23 @@ class O {
|
|
|
1078
1078
|
cp: `${c.speed}/${c.fo}/${c.dgo}`
|
|
1079
1079
|
})), M++;
|
|
1080
1080
|
}
|
|
1081
|
-
s.sort((c,
|
|
1082
|
-
const
|
|
1083
|
-
if (
|
|
1084
|
-
const c =
|
|
1085
|
-
let
|
|
1086
|
-
|
|
1087
|
-
let D = 2, Y = { combined: !1, speeds: [g], cost: (
|
|
1088
|
-
for (;
|
|
1089
|
-
const P = await O.combinedAnalyse(e, t, h, [c,
|
|
1090
|
-
if (Y.cost > P.cost ? E ? (E == null ? void 0 : E.cost) > P.cost && (E = P) : (E = Y, Y = P) : (!E || (E == null ? void 0 : E.cost) > P.cost) && (E = P),
|
|
1081
|
+
s.sort((c, f) => c.cost.total - f.cost.total);
|
|
1082
|
+
const y = s.at(0), g = s.at(1), m = [];
|
|
1083
|
+
if (m.push({ combined: !1, speeds: [y], cost: (w = y.cost) == null ? void 0 : w.total }), g) {
|
|
1084
|
+
const c = y.cost.cp, f = g.cost.cp, l = b(y.eta), u = b(y.etd), I = l.diff(u, "days", !0);
|
|
1085
|
+
let k = Math.ceil(I / 2);
|
|
1086
|
+
k = k > 7 ? 7 : k < e.alterStep ? e.alterStep : k;
|
|
1087
|
+
let D = 2, Y = { combined: !1, speeds: [g], cost: (p = g.cost) == null ? void 0 : p.total }, E;
|
|
1088
|
+
for (; k >= e.alterStep; ) {
|
|
1089
|
+
const P = await O.combinedAnalyse(e, t, h, [c, f], r, k, { ...a, level: D });
|
|
1090
|
+
if (Y.cost > P.cost ? E ? (E == null ? void 0 : E.cost) > P.cost && (E = P) : (E = Y, Y = P) : (!E || (E == null ? void 0 : E.cost) > P.cost) && (E = P), k <= e.alterStep)
|
|
1091
1091
|
break;
|
|
1092
|
-
|
|
1092
|
+
k = Math.ceil(k / 2), D += 1;
|
|
1093
1093
|
}
|
|
1094
|
-
|
|
1094
|
+
m.push(Y), E && m.push(E);
|
|
1095
1095
|
}
|
|
1096
|
-
const
|
|
1097
|
-
return
|
|
1096
|
+
const x = b().valueOf() - o;
|
|
1097
|
+
return S == null || S.info("[%s] analyse elapsed: %d ms", a == null ? void 0 : a.requestId, x), m.sort((c, f) => c.cost - f.cost);
|
|
1098
1098
|
}
|
|
1099
1099
|
/**
|
|
1100
1100
|
* 按步长多次减半,分别用7,4,2,1天步长及cpa,cpb交替计算各种组合下的成本
|
|
@@ -1106,12 +1106,24 @@ class O {
|
|
|
1106
1106
|
* @param step 步长,7,4,2,1
|
|
1107
1107
|
* @param options
|
|
1108
1108
|
*/
|
|
1109
|
-
static async combinedAnalyse(e, t, n,
|
|
1110
|
-
s.counter = 1,
|
|
1111
|
-
const d = await O.alternateAnalyse(e, t, n,
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1109
|
+
static async combinedAnalyse(e, t, n, r, a, o, s = {}) {
|
|
1110
|
+
s.counter = 1, S == null || S.info("[%s][L%d] analyse with alternate cp in every %d days", s.requestId, s.level, o);
|
|
1111
|
+
const d = await O.alternateAnalyse(e, t, n, r, 0, a, o, s), i = d.reduce((f, l) => f + l.cost.total, 0), h = d.reduce((f, l) => f + l.cost.hire, 0), M = d.reduce((f, l) => f + l.cost.bunker, 0), y = d.reduce((f, l) => f + l.distance, 0), g = d.reduce((f, l) => f + l.totalHrs, 0);
|
|
1112
|
+
S == null || S.info("[%s][L%d] cost with cpa/cpb turn: %j", s.requestId, s.level, {
|
|
1113
|
+
cost: i,
|
|
1114
|
+
hire: h,
|
|
1115
|
+
bunker: M,
|
|
1116
|
+
distance: y,
|
|
1117
|
+
hours: g
|
|
1118
|
+
});
|
|
1119
|
+
const m = await O.alternateAnalyse(e, t, n, r, 1, a, o, s), F = m.reduce((f, l) => f + l.cost.total, 0), x = m.reduce((f, l) => f + l.cost.hire, 0), w = m.reduce((f, l) => f + l.cost.bunker, 0), p = m.reduce((f, l) => f + l.distance, 0), c = m.reduce((f, l) => f + l.totalHrs, 0);
|
|
1120
|
+
return S == null || S.info("[%s][L%d] cost with cpb/cpa turn: %j", s.requestId, s.level, {
|
|
1121
|
+
cost: F,
|
|
1122
|
+
hire: x,
|
|
1123
|
+
bunker: w,
|
|
1124
|
+
distance: p,
|
|
1125
|
+
hours: c
|
|
1126
|
+
}), i < F ? { combined: !0, cost: Math.round(i * 1e3) / 1e3, speeds: d, step: o } : { combined: !0, cost: Math.round(F * 1e3) / 1e3, speeds: m, step: o };
|
|
1115
1127
|
}
|
|
1116
1128
|
/**
|
|
1117
1129
|
* 基于cp索引,交替计算指定步长下的成本
|
|
@@ -1124,44 +1136,44 @@ class O {
|
|
|
1124
1136
|
* @param step 步长,7,4,2,1
|
|
1125
1137
|
* @param options
|
|
1126
1138
|
*/
|
|
1127
|
-
static async alternateAnalyse(e, t, n,
|
|
1128
|
-
var
|
|
1129
|
-
let
|
|
1139
|
+
static async alternateAnalyse(e, t, n, r, a, o, s, d = {}) {
|
|
1140
|
+
var y, g;
|
|
1141
|
+
let i = b.utc(e.etd);
|
|
1130
1142
|
const h = { lat: e.lat, lng: e.lng }, M = [];
|
|
1131
|
-
for (;
|
|
1132
|
-
const
|
|
1143
|
+
for (; i.isBefore(n); ) {
|
|
1144
|
+
const m = i.clone().utc().add(s, "day"), F = JSON.parse(JSON.stringify(o.route)), x = JSON.parse(JSON.stringify(o.waypoints)), w = r[a], p = await O.analyseInstantWithThreshed(
|
|
1133
1145
|
h,
|
|
1134
|
-
|
|
1135
|
-
f,
|
|
1136
|
-
t,
|
|
1146
|
+
i.utc().format(),
|
|
1137
1147
|
m,
|
|
1148
|
+
t,
|
|
1149
|
+
w,
|
|
1150
|
+
F,
|
|
1138
1151
|
x,
|
|
1139
|
-
I,
|
|
1140
1152
|
e.meteoVendor,
|
|
1141
1153
|
e.speedStep,
|
|
1142
1154
|
e.useMeteo,
|
|
1143
1155
|
e.useRouteParam,
|
|
1144
1156
|
d
|
|
1145
1157
|
);
|
|
1146
|
-
|
|
1158
|
+
p && (await O.calculateCost(p, w, e, d), S == null || S.info(
|
|
1147
1159
|
"[%s][L%d-%d] analyse from %s to %s cost: %j",
|
|
1148
1160
|
d.requestId,
|
|
1149
1161
|
d.level,
|
|
1150
1162
|
d.counter,
|
|
1151
|
-
|
|
1152
|
-
|
|
1163
|
+
i.utc().format(),
|
|
1164
|
+
m.utc().format(),
|
|
1153
1165
|
{
|
|
1154
|
-
cost:
|
|
1155
|
-
hire:
|
|
1156
|
-
bunker:
|
|
1157
|
-
distance:
|
|
1158
|
-
hours:
|
|
1159
|
-
cp: `${
|
|
1166
|
+
cost: p.cost.total,
|
|
1167
|
+
hire: p.cost.hire,
|
|
1168
|
+
bunker: p.cost.bunker,
|
|
1169
|
+
distance: p.distance,
|
|
1170
|
+
hours: p.totalHrs,
|
|
1171
|
+
cp: `${w.speed}/${w.fo}/${w.dgo}`
|
|
1160
1172
|
}
|
|
1161
1173
|
)), d.counter = d.counter + 1;
|
|
1162
|
-
const c = (g = (
|
|
1174
|
+
const c = (g = (y = p == null ? void 0 : p.sample) == null ? void 0 : y.hours) == null ? void 0 : g.at(-1);
|
|
1163
1175
|
if (c)
|
|
1164
|
-
h.lat = c.lat, h.lng = c.lng,
|
|
1176
|
+
h.lat = c.lat, h.lng = c.lng, i = b(c.eta), M.push(p), a = a ? 0 : 1;
|
|
1165
1177
|
else
|
|
1166
1178
|
break;
|
|
1167
1179
|
}
|
|
@@ -1174,7 +1186,7 @@ class O {
|
|
|
1174
1186
|
* @param props
|
|
1175
1187
|
* @param options
|
|
1176
1188
|
*/
|
|
1177
|
-
static async calculateCost(e, t, n,
|
|
1189
|
+
static async calculateCost(e, t, n, r = {}) {
|
|
1178
1190
|
var a;
|
|
1179
1191
|
if (e) {
|
|
1180
1192
|
const o = Math.round(e.totalHrs / 24 * (n.dailyHire || 0) * (1 - (n.addComm || 0)) * 1e3) / 1e3, s = Math.round(e.totalFoCons * (n.priceFO || 0) * 1e3) / 1e3, d = Math.round((e.totalDgoCons + (((a = e.extend) == null ? void 0 : a.totalDgoConsInECA) || 0)) * (n.priceDGO || 0) * 1e3) / 1e3;
|
|
@@ -1191,22 +1203,22 @@ class O {
|
|
|
1191
1203
|
* 计算单cp模式下的ECA属性
|
|
1192
1204
|
*/
|
|
1193
1205
|
static async calculateECA(e, t, n = {}) {
|
|
1194
|
-
var d,
|
|
1195
|
-
const
|
|
1206
|
+
var d, i;
|
|
1207
|
+
const r = await W.intersectInECA(e.route);
|
|
1196
1208
|
let a = 0, o = 0, s = 0;
|
|
1197
1209
|
e.sample.wps.forEach((h) => {
|
|
1198
1210
|
h.positionTime = b.utc(h.etd || h.eta).unix();
|
|
1199
1211
|
});
|
|
1200
|
-
for (const h of
|
|
1212
|
+
for (const h of r) {
|
|
1201
1213
|
a += h.distance;
|
|
1202
|
-
const M = await W.deadReckoningTime((d = h.waypoints) == null ? void 0 : d.at(0), e.sample.wps),
|
|
1203
|
-
h.in = M, h.out =
|
|
1214
|
+
const M = await W.deadReckoningTime((d = h.waypoints) == null ? void 0 : d.at(0), e.sample.wps), y = await W.deadReckoningTime((i = h.waypoints) == null ? void 0 : i.at(-1), e.sample.wps);
|
|
1215
|
+
h.in = M, h.out = y, h.totalHrs = J.roundPrecision((y.positionTime - M.positionTime) / 3600, 2), h.totalDgoCons = J.roundPrecision(t.fo / 24 * h.totalHrs, 3), o += h.totalHrs, s += h.totalDgoCons;
|
|
1204
1216
|
}
|
|
1205
1217
|
return a = J.roundPrecision(a, 3), o = J.roundPrecision(o, 3), s = J.roundPrecision(s, 3), {
|
|
1206
1218
|
distanceInECA: a,
|
|
1207
1219
|
hoursInECA: o,
|
|
1208
1220
|
totalDgoConsInECA: s,
|
|
1209
|
-
eca:
|
|
1221
|
+
eca: r
|
|
1210
1222
|
};
|
|
1211
1223
|
}
|
|
1212
1224
|
/**
|
|
@@ -1215,55 +1227,55 @@ class O {
|
|
|
1215
1227
|
* @param options
|
|
1216
1228
|
*/
|
|
1217
1229
|
static async mergeSpeeds(e, t = {}) {
|
|
1218
|
-
var c,
|
|
1230
|
+
var c, f;
|
|
1219
1231
|
const n = {
|
|
1220
1232
|
hours: [],
|
|
1221
1233
|
wps: [],
|
|
1222
1234
|
days: []
|
|
1223
|
-
},
|
|
1224
|
-
var
|
|
1225
|
-
return
|
|
1226
|
-
}, 0), o = e.reduce((
|
|
1227
|
-
var
|
|
1228
|
-
return
|
|
1229
|
-
}, 0), d = e.reduce((
|
|
1230
|
-
var
|
|
1231
|
-
return
|
|
1232
|
-
}, 0),
|
|
1233
|
-
let
|
|
1234
|
-
for (const
|
|
1235
|
-
|
|
1236
|
-
const u =
|
|
1237
|
-
|
|
1238
|
-
N && (T.distanceFromStart = T.distanceFromStart +
|
|
1239
|
-
}),
|
|
1240
|
-
N && (T.distanceFromStart = T.distanceFromStart +
|
|
1241
|
-
}),
|
|
1242
|
-
N && (T.distanceFromStart = T.distanceFromStart +
|
|
1243
|
-
})), D.cp =
|
|
1244
|
-
const Y = [
|
|
1245
|
-
E === -1 ? (D.cp.segment = [Y],
|
|
1235
|
+
}, r = e.reduce((l, u) => l + u.distance, 0), a = e.reduce((l, u) => {
|
|
1236
|
+
var I;
|
|
1237
|
+
return l + (((I = u.extend) == null ? void 0 : I.distanceInECA) || 0);
|
|
1238
|
+
}, 0), o = e.reduce((l, u) => l + u.totalHrs, 0), s = e.reduce((l, u) => {
|
|
1239
|
+
var I;
|
|
1240
|
+
return l + (((I = u.extend) == null ? void 0 : I.hoursInECA) || 0);
|
|
1241
|
+
}, 0), d = e.reduce((l, u) => {
|
|
1242
|
+
var I;
|
|
1243
|
+
return l + (((I = u.extend) == null ? void 0 : I.totalDgoConsInECA) || 0);
|
|
1244
|
+
}, 0), i = e.reduce((l, u) => l + u.wxFactor * u.totalHrs / o, 0), h = e.reduce((l, u) => l + u.cFactor * u.totalHrs / o, 0), M = e.reduce((l, u) => l + u.totalFoCons, 0), y = e.reduce((l, u) => l + u.totalDgoCons, 0), g = e.reduce((l, u) => l + u.cost.total, 0), m = e.reduce((l, u) => l + u.cost.hire, 0), F = e.reduce((l, u) => l + u.cost.bunker, 0), x = [], w = [];
|
|
1245
|
+
let p;
|
|
1246
|
+
for (const l of e) {
|
|
1247
|
+
w.push(...((c = l.extend) == null ? void 0 : c.eca) || []);
|
|
1248
|
+
const u = l.sample.hours, I = l.sample.wps, k = l.sample.days, D = u.at(0);
|
|
1249
|
+
p && (D.distanceFromPrevious = p.distanceFromPrevious, D.distanceFromStart = p.distanceFromStart, u.forEach((T, N) => {
|
|
1250
|
+
N && (T.distanceFromStart = T.distanceFromStart + p.distanceFromStart);
|
|
1251
|
+
}), I.at(0).distanceFromPrevious = p.distanceFromPrevious, I.at(0).distanceFromStart = p.distanceFromStart, I.forEach((T, N) => {
|
|
1252
|
+
N && (T.distanceFromStart = T.distanceFromStart + p.distanceFromStart);
|
|
1253
|
+
}), k.at(0).distanceFromPrevious = p.distanceFromPrevious, k.at(0).distanceFromStart = p.distanceFromStart, k.forEach((T, N) => {
|
|
1254
|
+
N && (T.distanceFromStart = T.distanceFromStart + p.distanceFromStart);
|
|
1255
|
+
})), D.cp = l.cost.cp;
|
|
1256
|
+
const Y = [l.etd, l.eta], E = x.findIndex((T) => T.id === D.cp.id);
|
|
1257
|
+
E === -1 ? (D.cp.segment = [Y], x.push(D.cp)) : x[E].segment.push(Y), u.forEach((T) => {
|
|
1246
1258
|
var A;
|
|
1247
1259
|
((A = n.hours) == null ? void 0 : A.findIndex((R) => R.eta === T.eta)) === -1 && n.hours.push(T);
|
|
1248
|
-
}),
|
|
1260
|
+
}), I.forEach((T) => {
|
|
1249
1261
|
var A;
|
|
1250
1262
|
((A = n.wps) == null ? void 0 : A.findIndex((R) => R.eta === T.eta)) === -1 && n.wps.push(T);
|
|
1251
|
-
}),
|
|
1263
|
+
}), k.forEach((T) => {
|
|
1252
1264
|
var A;
|
|
1253
1265
|
((A = n == null ? void 0 : n.days) == null ? void 0 : A.findIndex((R) => R.eta === T.eta)) === -1 && n.days.push(T);
|
|
1254
1266
|
});
|
|
1255
|
-
const P = (
|
|
1256
|
-
P === -1 ? n.wps.push(D) : n.wps[P] = D,
|
|
1267
|
+
const P = (f = n.wps) == null ? void 0 : f.findIndex((T) => T.eta === D.eta);
|
|
1268
|
+
P === -1 ? n.wps.push(D) : n.wps[P] = D, p = u.at(-1);
|
|
1257
1269
|
}
|
|
1258
|
-
return n.wps.sort((
|
|
1259
|
-
b(
|
|
1260
|
-
}), n.wps.forEach((
|
|
1261
|
-
const
|
|
1262
|
-
if (
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
const E = W.calculateBearing(
|
|
1266
|
-
|
|
1270
|
+
return n.wps.sort((l, u) => {
|
|
1271
|
+
b(l.etd).unix() - b(u.etd).unix();
|
|
1272
|
+
}), n.wps.forEach((l, u) => {
|
|
1273
|
+
const I = n.wps[u - 1];
|
|
1274
|
+
if (I) {
|
|
1275
|
+
const k = l.distanceFromStart - (I.distanceFromStart || 0), D = b(l.eta || l.etd).diff(b(I.etd || I.eta), "hour", !0), Y = Math.round(k / D * 100) / 100;
|
|
1276
|
+
l.avgSpd = Y;
|
|
1277
|
+
const E = W.calculateBearing(I, l);
|
|
1278
|
+
I.bearing = E;
|
|
1267
1279
|
}
|
|
1268
1280
|
}), {
|
|
1269
1281
|
sample: n,
|
|
@@ -1273,21 +1285,21 @@ class O {
|
|
|
1273
1285
|
to: e.at(-1).to,
|
|
1274
1286
|
v0: e.at(0).v0,
|
|
1275
1287
|
label: "Combined",
|
|
1276
|
-
distance: Math.round(
|
|
1288
|
+
distance: Math.round(r * 1e4) / 1e4,
|
|
1277
1289
|
totalHrs: Math.round(o * 1e3) / 1e3,
|
|
1278
|
-
avgSpeed: Math.round(
|
|
1279
|
-
wxFactor: Math.round(
|
|
1290
|
+
avgSpeed: Math.round(r / o * 1e3) / 1e3,
|
|
1291
|
+
wxFactor: Math.round(i * 1e3) / 1e3,
|
|
1280
1292
|
cFactor: Math.round(h * 1e3) / 1e3,
|
|
1281
1293
|
totalFoCons: Math.round(M * 1e3) / 1e3,
|
|
1282
|
-
totalDgoCons: Math.round(
|
|
1294
|
+
totalDgoCons: Math.round(y * 1e3) / 1e3,
|
|
1283
1295
|
cost: {
|
|
1284
1296
|
total: Math.round(g * 1e3) / 1e3,
|
|
1285
|
-
hire: Math.round(
|
|
1286
|
-
bunker: Math.round(
|
|
1297
|
+
hire: Math.round(m * 1e3) / 1e3,
|
|
1298
|
+
bunker: Math.round(F * 1e3) / 1e3
|
|
1287
1299
|
},
|
|
1288
1300
|
extend: {
|
|
1289
|
-
cps:
|
|
1290
|
-
eca:
|
|
1301
|
+
cps: x,
|
|
1302
|
+
eca: w,
|
|
1291
1303
|
distanceInECA: Math.round(a * 1e4) / 1e4,
|
|
1292
1304
|
hoursInECA: Math.round(s * 1e3) / 1e3,
|
|
1293
1305
|
totalDgoConsInECA: Math.round(d * 1e3) / 1e3,
|