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