@idm-plugin/vessel 1.1.9 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +738 -379
- package/dist/index.umd.cjs +1 -1
- package/dist/speed/src/index.d.ts +216 -0
- package/package.json +1 -1
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(j,y){typeof exports=="object"&&typeof module<"u"?y(exports,require("got"),require("@log4js-node/log4js-api"),require("moment")):typeof define=="function"&&define.amd?define(["exports","got","@log4js-node/log4js-api","moment"],y):(j=typeof globalThis<"u"?globalThis:j||self,y(j["idm-plugin-rabbitmq"]={},j.got,j["@log4js-node/log4js-api"],j.moment))})(this,function(j,y,E,g){"use strict";var U=Object.defineProperty;var J=(j,y,E)=>y in j?U(j,y,{enumerable:!0,configurable:!0,writable:!0,value:E}):j[y]=E;var A=(j,y,E)=>(J(j,typeof y!="symbol"?y+"":y,E),E);const b=E.getLogger("vessel");class V{parseStatus(p){let e,a;switch(p){case 0:e="在航(主机推动)",a="The engine is in use";break;case 1:e="锚泊",a="Anchored";break;case 2:e="失控",a="Not operated";break;case 3:e="操纵受限",a="Limited airworthiness";break;case 4:e="吃水受限",a="Limited by ship's draft";break;case 5:e="靠泊",a="Mooring";break;case 6:e="搁浅",a="Stranded";break;case 7:e="捕捞作业",a="Engaged in fishing";break;case 8:e="靠帆船提供动力",a="Sailing";break;default:e="未定义",a="Undefined"}return{labelCn:e,labelEn:a}}}class L extends V{constructor(e,a){super();A(this,"clientId");A(this,"clientSecret");A(this,"token");this.clientId=e,this.clientSecret=a}async authToken(e={}){const a="https://svc.data.myvessel.cn/ada/oauth/token",n={searchParams:{client_id:this.clientId,client_secret:this.clientSecret,grant_type:"client_credentials"}},o=await y.post(a,n).json();b.info("[%s] fetch access token from: %s - %j",e.requestId,a,o),o.error||(this.token={accessToken:o.access_token,tokenType:o.token_type,expiresIn:o.expires_in,scope:o.scope,jti:o.jti,issuedAt:g().utc().format()})}async realTimePosition(e,a={}){var d,c,l;(!this.token||g().diff(g(this.token.issuedAt),"seconds")>((d=this.token)==null?void 0:d.expiresIn)-300)&&await this.authToken(a);const n="https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit",o={headers:{Authorization:`${(c=this.token)==null?void 0:c.tokenType} ${(l=this.token)==null?void 0:l.accessToken}`},searchParams:{mmsi:e}};b.info("[%s] fetch realtime position from: %s - %j",a.requestId,n,o);const s=await y.get(n,o).json();if(s.code)return b.warn("[%s] fetch realtime position failed: %j",a.requestId,n,{message:s.message,status:s.status,code:s.code}),s;const t=s.data;for(const u in t)!isNaN(t[u])&&Number(t[u])!==1/0&&(t[u]=Number(t[u]));const r=g(`${t.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:t.mmsi,name:t.vesselName,imo:t.imo,callSign:t.callsign,lat:t.lat,lng:t.lon,length:t.length,width:t.width,draught:t.currDraught,sog:t.sog,cog:t.cog,hdg:t.hdg,rot:t.rot,eta:t.eta,destination:t.dest,positionTime:r.unix(),status:t.status,labelCn:t.statusNameCn,labelEn:t.statusNameEn,method:"position",vendor:"myVessel",utc:r.utc().format()}}async trajectory(e,a,n,o,s=!0,t={}){(!this.token||g().diff(g(this.token.issuedAt),"seconds")>this.token.expiresIn-300)&&await this.authToken(t);const r=await this.realTimePosition(e,t),i=g(a),d=g(n),c=[];for(;d.diff(i,"day",!0)>30;)await this.trajectoryIn30Day(e,i,i.clone().add(30,"day"),r,o,c,t),i.add(30,"day");return await this.trajectoryIn30Day(e,i,d,r,o,c,t),c}async trajectoryIn30Day(e,a,n,o,s,t,r={}){var h,I,Y,k,w;const i="https://svc.data.myvessel.cn/sdc/v1/vessels/status/track",d={headers:{Authorization:`${(h=this.token)==null?void 0:h.tokenType} ${(I=this.token)==null?void 0:I.accessToken}`},json:{mmsi:e,startTime:a.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),endTime:n.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")}};b.info("[%s] fetch trajectory from: %s - %j",r.requestId,i,d);const c=await y.post(i,d).json();if(c.code)return b.warn("[%s] fetch trajectory failed: %j",r.requestId,i,{message:c.message,status:c.status,code:c.code}),c;let l=-1;const u=g(`${(k=(Y=c.data)==null?void 0:Y[0])==null?void 0:k.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return(w=c.data)==null||w.forEach(m=>{for(const T in m)!isNaN(m[T])&&Number(m[T])!==1/0&&(m[T]=Number(m[T]));const v=g(`${m.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"),N=m.eta?g(`${m.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"):void 0,f=m.status,{labelCn:q,labelEn:R}=this.parseStatus(f),P={mmsi:m.mmsi,imo:o==null?void 0:o.imo,lat:m.lat,lng:m.lon,sog:m.sog,cog:m.cog,hdg:m.hdg,draught:m.draught,status:f,eta:N==null?void 0:N.unix(),destination:m.dest,positionTime:v.unix(),labelCn:q,labelEn:R,method:"trajectory",vendor:"myVessel",utc:v.utc().format()},x=Math.floor(v.diff(u,"minute",!0)/(s||1));x!==l&&(l=x,t.push(P))}),t}}class z extends V{constructor(e){super();A(this,"token");this.token=e}async realTimePosition(e,a={}){const n="https://api.hifleet.com/position/position/get/token",o={searchParams:{mmsi:e,usertoken:this.token}},s=await y.post(n,o).json();b.info("[%s] fetch realtime position from: %s - %j",a.requestId,n,o);const t=s==null?void 0:s.list;if(!t)return b.warn("[%s] fetch realtime position failed: %j",a.requestId,n,s),s;for(const u in t)!isNaN(t[u])&&Number(t[u])!==1/0&&(t[u]=Number(t[u]));t.status=t.sp>3?0:1;const r=t.status,{labelCn:i,labelEn:d}=this.parseStatus(r),c=g(`${t.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:t.m,name:t.n,imo:t.imonumber,callSign:t.callsign,lat:Math.round(t.la/60*1e5)/1e5,lng:Math.round(t.lo/60*1e5)/1e5,length:t.l,width:t.w,draught:t.draught,sog:t.sp,cog:t.co,hdg:t.h,rot:isNaN(t.rot)?0:t.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(t.eta)?g(`${t.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00").unix():void 0,destination:t.destination,positionTime:c.unix(),utc:c.utc().format(),status:r,labelCn:i,labelEn:d,method:"position",vendor:"hifleet"}}async search(e,a={}){let n="https://www.hifleet.com/hifleetapi/searchVesselOL.do";const o={searchParams:{keyword:e},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}};let s=await y.post(n,o).json();b.info("[%s] fetch vessel props from: %s - %j",a.requestId,n,o),s instanceof Array&&(s=s[0]);for(const r in s)!isNaN(s[r])&&Number(s[r])!==1/0&&(s[r]=Number(s[r]));const t={mmsi:s.m,name:s.n,imo:s.i,callSign:s.c,length:s.l,breadth:s.b,draught:s.dr};return n="https://www.hifleet.com/hifleetapi/sameShipSearch.do",s=await y.post(n,o).json(),b.info("[%s] fetch vessel dead weight from: %s - %j",a.requestId,n,o),s instanceof Array&&(s=s[0]),s&&(t.deadweight=Number(s.dwt)),t}async trajectory(e,a,n,o,s=!0,t={}){var m,v,N;const r=await this.realTimePosition(e,t);let i=g(a);const d=g(n),c=g();if(s){let f=d.diff(i,"d",!0);f<0?i=d.clone().subtract(40,"d"):f<30?i.subtract(10,"d"):f<60?i.subtract(5,"d"):i=d.clone().subtract(80,"d"),f=c.diff(d,"d",!0),d.add(f>10?240:f*24,"h")}const l={searchParams:{endtime:d.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),starttime:i.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),mmsi:e,usertoken:this.token}},u="https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",h=await y.get(u,l).json();b.info("[%s] fetch trajectory from: %s - %j",t.requestId,u,l);let I;h&&(I=((v=(m=h.ships)==null?void 0:m.offors)==null?void 0:v.ship)||[],I.length||b.warn("[%s] fetch trajectory failed: %j",t.requestId,h));const Y=[];let k=-1;const w=g(`${(N=I==null?void 0:I[0])==null?void 0:N.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");for(const f of I){for(const _ in f)!isNaN(f[_])&&Number(f[_])!==1/0&&(f[_]=Number(f[_]));const q=g(`${f.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");f.status=f.sp>4?0:1;const{labelEn:R,labelCn:P}=this.parseStatus(f.status),x={mmsi:f.m,name:f.n,imo:r==null?void 0:r.imo,lat:f.la,lng:f.lo,draught:f.draught,sog:f.sp,cog:f.co,hdg:f.hdg,positionTime:q.unix(),utc:q.utc().format(),status:f.status,labelCn:P,labelEn:R,method:"trajectory",vendor:"hifleet"},T=Math.floor(q.diff(w,"minute",!0)/(o||1));T!==k&&(k=T,Y.push(x))}return Y}}class F extends V{constructor(e){super();A(this,"token");this.token=e}async realTimePosition(e,a={}){const n={searchParams:{id:e,k:this.token,enc:1}},o="https://api.shipxy.com/apicall/GetSingleShip",s=await y.get(o,n).json();if(b.info("[%s] fetch realtime position from: %s - %j",a.requestId,o,n),(s==null?void 0:s.status)!==0)return s;const t=s.data[0];for(const l in t)!isNaN(t[l])&&Number(t[l])!==1/0&&(t[l]=Number(t[l]));const{labelCn:r,labelEn:i}=await this.parseStatus(t.navistat),d=g.unix(t.lasttime);return{mmsi:t.ShipID,name:t.name,imo:t.imo,callSign:t.callsign,lat:Math.round(t.lat/1e6*1e5)/1e5,lng:Math.round(t.lon/1e6*1e5)/1e5,length:Math.round(t.length/10*100)/100,width:Math.round(t.width/10*100)/100,draught:Math.round(t.draught/1e3*100)/100,sog:Math.round(t.sog*3600/1e3/1852*100)/100,cog:Math.round(t.cog/100*100)/100,hdg:Math.round(t.hdg/100*100)/100,rot:Math.round(t.rot/100*100)/100,positionTime:t.lasttime,utc:d.utc().format(),status:t.navistat,labelEn:i,labelCn:r,method:"position",vendor:"shipxy"}}async trajectory(e,a,n,o,s=!0,t={}){var w;const r=await this.realTimePosition(e,t),i=g(a),d=g(n),c="https://api.shipxy.com/apicall/GetShipTrack",l={searchParams:{id:e,k:this.token,enc:1,cut:0,btm:i.unix(),etm:d.unix()}},u=await y.get(c,l).json();if(b.info("[%s] fetch trajectory from: %s - %j",t.requestId,c,l),(u==null?void 0:u.status)!==0)return u;const h=u==null?void 0:u.points,I=[],Y=g.unix((w=h[0])==null?void 0:w.utc);let k=-1;for(const m of h){const v=g.unix(m.utc),N={imo:r==null?void 0:r.imo,mmsi:e,sog:Math.round(m.sog*3600/1e3/1852*100)/100,cog:Math.round(m.cog/100*100)/100,lat:Math.round(m.lat/1e6*1e5)/1e5,lng:Math.round(m.lon/1e6*1e5)/1e5,positionTime:v.unix(),utc:v.utc().format(),method:"trajectory",vendor:"shipxy"},f=Math.floor(v.diff(Y,"minute",!0)/(o||1));f!==k&&(k=f,I.push(N))}return I}}class G extends V{constructor(e){super();A(this,"token");this.token=e}async getShipId(e,a={}){const n={headers:{appKey:this.token},json:{mmsiList:e}},o="https://api3.myships.com/sp/ships/getShipIdByMMSI",s=await y.post(o,n).json();return b.info("[%s] fetch ship id from: %s - %j",a.requestId,o,n),s.code!=="0"?s:s.data[0].shipId}async getShipInfo(e,a={}){const n={headers:{appKey:this.token},json:{shipId:e}},o="https://api3.myships.com/sp/ships/aissta",s=await y.post(o,n).json();if(b.info("[%s] fetch ship info from: %s - %j",a.requestId,o,n),s.code!=="0")return s;const t=s.data;let r=t.imo;return e==="407170"&&(r="9198379",b.warn("[%s] ship(%s) imo error: %s, should be %s",a.requestId,e,t.imo,r)),{mmsi:t.mmsi,name:t.shipnameEn,imo:r,callSign:t.callSign,length:t.length,width:t.breadth,draught:(t.draught||100)/10}}async realTimePosition(e,a={}){const n=await this.getShipId(e,a),o=await this.getShipInfo(n,a),s={headers:{appKey:this.token},json:{shipId:n}},t="https://api3.myships.com/sp/ships/position/latest",r=await y.post(t,s).json();b.info("[%s] fetch realtime position from: %s - %j",a.requestId,t,s);const i=r.data[0];for(const h in i)!isNaN(i[h])&&Number(i[h])!==1/0&&(i[h]=Number(i[h]));const{labelCn:d,labelEn:c}=await this.parseStatus(i.aisNavStatus),l=g.unix(i.posTime);return{...o,mmsi:e,lat:Math.round(i.lat/1e4/60*1e5)/1e5,lng:Math.round(i.lon/1e4/60*1e5)/1e5,sog:Math.round(i.sog/10*100)/100,cog:Math.round(i.cog/10*100)/100,hdg:Math.round(i.heading*100)/100,rot:Math.round(i.rot*100)/100,positionTime:i.posTime,utc:l.utc().format(),status:i.aisNavStatus,labelEn:c,labelCn:d,method:"position",vendor:"myship"}}async trajectory(e,a,n,o,s=!0,t={}){const r=g(a),i=g(n),d=await this.getShipId(e),c=await this.getShipInfo(d),l=[];for(;i.diff(r,"day",!0)>30;)await this.trajectoryIn30Day(d,r.unix(),r.add(30,"day").unix(),c,e,o,l);return await this.trajectoryIn30Day(d,r.unix(),i.unix(),c,e,o,l),l}async trajectoryIn30Day(e,a,n,o,s,t,r,i={}){var Y;const d={headers:{appKey:this.token},json:{shipId:e,startTime:a,endTime:n}},c="https://api3.myships.com/sp/ships/position/history",l=await y.post(c,d).json();if(b.info("[%s] fetch trajectory from: %s - %j",i.requestId,c,d),l.code!=="0")return b.warn("[%s] invoke myship trajectory failed: %j",i.requestId,l),l;const u=l.data;for(const k in u)!isNaN(u[k])&&Number(u[k])!==1/0&&(u[k]=Number(u[k]));const h=g.unix((Y=u[0])==null?void 0:Y.posTime);let I=-1;for(const k of u){const w=g.unix(k.posTime),m={imo:o==null?void 0:o.imo,mmsi:s,lat:Math.round(k.lat/1e4/60*1e5)/1e5,lng:Math.round(k.lon/1e4/60*1e5)/1e5,sog:Math.round(k.sog/10*100)/100,cog:Math.round(k.cog/10*100)/100,hdg:Math.round(k.heading*100)/100,rot:Math.round(k.rot*100)/100,positionTime:w.unix(),utc:w.utc().format(),method:"trajectory",vendor:"myship"},v=Math.floor(w.diff(h,"minute",!0)/(t||1));v!==I&&(I=v,r.push(m))}return r}}const O=E.getLogger("vessel");var C=(S=>(S.NOTICE="NOTICE",S.WARN="WARN",S.HEAVY="HEAVY",S.SEVERE="SEVERE",S.ERROR="ERROR",S.FATAL="FATAL",S))(C||{});class K{parsePrinciple(p,e={}){var t,r,i;O.info("[%s] parse rule: %s",e.requestId,p);const a=new RegExp("(?<=\\[)(.+)(?=])","g"),n=p.match(a)?(t=p.match(a))==null?void 0:t[0]:void 0,o=n==null?void 0:n.split(";");if(!o)return;const s={};for(let d=0;d<(o==null?void 0:o.length);d++){const c=(i=(r=o[d].match(a))==null?void 0:r[0])==null?void 0:i.split("],");if(d===0&&!c)s.scope=o[0];else if(c)for(let l=0,u=c.length;l<u;l++){const h=this.parseRule(c[l]);h&&(s[h.level]?h.key?s[h.level][h==null?void 0:h.key]=h:s[h.level]=h:h.key?s[h.level]={[h==null?void 0:h.key]:h}:s[h.level]=h)}}return s}parseRule(p,e={}){var s;O.info("[%s] parse rule: %s",e.requestId,p),p=p.startsWith("[")?p:`[${p}`,p=p.endsWith("]")?p:`${p}]`;const a=new RegExp("(?<=\\[)(.+?)(?=])","g"),n=(s=p==null?void 0:p.match(a))==null?void 0:s[0],o=n==null?void 0:n.split(",");if(o)return{operator:o[0],number:Number.isNaN(Number(o[1]))?o[1]:Number(o[1]),level:o[2],time:Number(o[3]),key:o[4]}}checkWeather(p,e,a={}){var h,I,Y,k,w,m,v,N,f,q,R,P,x,T,_;let n=0,o=0,s=0,t=0;const r=Math.round(((I=(h=e==null?void 0:e.SEVERE)==null?void 0:h.sigWave)==null?void 0:I.number)*1.6*100)/100,i=(k=(Y=e==null?void 0:e.SEVERE)==null?void 0:Y.sigWave)==null?void 0:k.number,d=(m=(w=e==null?void 0:e.HEAVY)==null?void 0:w.sigWave)==null?void 0:m.number,c=Math.round((((N=(v=e==null?void 0:e.SEVERE)==null?void 0:v.wind)==null?void 0:N.number)+2)*100)/100,l=(q=(f=e==null?void 0:e.SEVERE)==null?void 0:f.wind)==null?void 0:q.number,u=(P=(R=e==null?void 0:e.HEAVY)==null?void 0:R.wind)==null?void 0:P.number;for(let $=0;$<(p==null?void 0:p.length);$++){const M=p[$],H=(T=(x=M==null?void 0:M.meteo)==null?void 0:x.wave)==null?void 0:T.sig,D=(_=M==null?void 0:M.meteo)==null?void 0:_.wind,W=$?g(M.eta).diff(g(p[$-1].eta),"hour",!0):0;t=W>t?W:t,O.info("[%s] check sig.wave: %j",a.requestId,{...H,dgThd4Wv:r,svThd4Wv:i,hvThd4Wv:d}),(H==null?void 0:H.height)>=r?M.isDangerous=!0:(H==null?void 0:H.height)>=i?M.isSevere=!0:(H==null?void 0:H.height)>=d&&(M.isHeavy=!0),O.info("[%s] check wind: %j",a.requestId,{...D,dgThd4Wd:c,svThd4Wd:l,hvThd4Wd:u}),(D==null?void 0:D.scale)>=c?(M.isDangerous=!0,delete M.isSevere,delete M.isHeavy):(D==null?void 0:D.scale)>l?(M.isDangerous||(M.isSevere=!0),delete M.isHeavy):(D==null?void 0:D.scale)===u&&!M.isDangerous&&!M.isSevere&&(M.isHeavy=!0),n+=M.isDangerous?W:0,o+=M.isSevere?W:0,s+=M.isHeavy?W:0}return n=Math.round(n*100)/100,o=Math.round(o*100)/100,s=Math.round(s*100)/100,t=Math.round(t),{sample:p,dangerous:n,severe:o,heavy:s,step:t<3?3:t,wind:{dgThd4Wd:c,svThd4Wd:l,hvThd4Wd:u},sig:{dgThd4Wv:r,svThd4Wv:i,hvThd4Wv:d}}}}const B=new K;j.AISImpl=V,j.AlertHelper=K,j.AlertLevel=C,j.HifleetImpl=z,j.MyShipImpl=G,j.MyVesselImpl=L,j.ShipxyImpl=F,j.alertHelper=B,Object.defineProperty(j,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(j,Y){typeof exports=="object"&&typeof module<"u"?Y(exports,require("got"),require("@log4js-node/log4js-api"),require("moment"),require("@idm-plugin/geo"),require("@idm-plugin/meteo")):typeof define=="function"&&define.amd?define(["exports","got","@log4js-node/log4js-api","moment","@idm-plugin/geo","@idm-plugin/meteo"],Y):(j=typeof globalThis<"u"?globalThis:j||self,Y(j["idm-plugin-rabbitmq"]={},j.got,j["@log4js-node/log4js-api"],j.moment,j["@idm-plugin/geo"],j["@idm-plugin/meteo"]))})(this,function(j,Y,R,y,x,st){"use strict";var dt=Object.defineProperty;var ut=(j,Y,R)=>Y in j?dt(j,Y,{enumerable:!0,configurable:!0,writable:!0,value:R}):j[Y]=R;var _=(j,Y,R)=>(ut(j,typeof Y!="symbol"?Y+"":Y,R),R);const D=R.getLogger("vessel");class Z{parseStatus(a){let t,i;switch(a){case 0:t="在航(主机推动)",i="The engine is in use";break;case 1:t="锚泊",i="Anchored";break;case 2:t="失控",i="Not operated";break;case 3:t="操纵受限",i="Limited airworthiness";break;case 4:t="吃水受限",i="Limited by ship's draft";break;case 5:t="靠泊",i="Mooring";break;case 6:t="搁浅",i="Stranded";break;case 7:t="捕捞作业",i="Engaged in fishing";break;case 8:t="靠帆船提供动力",i="Sailing";break;default:t="未定义",i="Undefined"}return{labelCn:t,labelEn:i}}}class at extends Z{constructor(t,i){super();_(this,"clientId");_(this,"clientSecret");_(this,"token");this.clientId=t,this.clientSecret=i}async authToken(t={}){const i="https://svc.data.myvessel.cn/ada/oauth/token",o={searchParams:{client_id:this.clientId,client_secret:this.clientSecret,grant_type:"client_credentials"}},n=await Y.post(i,o).json();D.info("[%s] fetch access token from: %s - %j",t.requestId,i,n),n.error||(this.token={accessToken:n.access_token,tokenType:n.token_type,expiresIn:n.expires_in,scope:n.scope,jti:n.jti,issuedAt:y().utc().format()})}async realTimePosition(t,i={}){var m,g,p;(!this.token||y().diff(y(this.token.issuedAt),"seconds")>((m=this.token)==null?void 0:m.expiresIn)-300)&&await this.authToken(i);const o="https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit",n={headers:{Authorization:`${(g=this.token)==null?void 0:g.tokenType} ${(p=this.token)==null?void 0:p.accessToken}`},searchParams:{mmsi:t}};D.info("[%s] fetch realtime position from: %s - %j",i.requestId,o,n);const s=await Y.get(o,n).json();if(s.code)return D.warn("[%s] fetch realtime position failed: %j",i.requestId,o,{message:s.message,status:s.status,code:s.code}),s;const e=s.data;for(const f in e)!isNaN(e[f])&&Number(e[f])!==1/0&&(e[f]=Number(e[f]));const d=y(`${e.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:e.mmsi,name:e.vesselName,imo:e.imo,callSign:e.callsign,lat:e.lat,lng:e.lon,length:e.length,width:e.width,draught:e.currDraught,sog:e.sog,cog:e.cog,hdg:e.hdg,rot:e.rot,eta:e.eta,destination:e.dest,positionTime:d.unix(),status:e.status,labelCn:e.statusNameCn,labelEn:e.statusNameEn,method:"position",vendor:"myVessel",utc:d.utc().format()}}async trajectory(t,i,o,n,s=!0,e={}){(!this.token||y().diff(y(this.token.issuedAt),"seconds")>this.token.expiresIn-300)&&await this.authToken(e);const d=await this.realTimePosition(t,e),r=y(i),m=y(o),g=[];for(;m.diff(r,"day",!0)>30;)await this.trajectoryIn30Day(t,r,r.clone().add(30,"day"),d,n,g,e),r.add(30,"day");return await this.trajectoryIn30Day(t,r,m,d,n,g,e),g}async trajectoryIn30Day(t,i,o,n,s,e,d={}){var l,b,w,u,c;const r="https://svc.data.myvessel.cn/sdc/v1/vessels/status/track",m={headers:{Authorization:`${(l=this.token)==null?void 0:l.tokenType} ${(b=this.token)==null?void 0:b.accessToken}`},json:{mmsi:t,startTime:i.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),endTime:o.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")}};D.info("[%s] fetch trajectory from: %s - %j",d.requestId,r,m);const g=await Y.post(r,m).json();if(g.code)return D.warn("[%s] fetch trajectory failed: %j",d.requestId,r,{message:g.message,status:g.status,code:g.code}),g;let p=-1;const f=y(`${(u=(w=g.data)==null?void 0:w[0])==null?void 0:u.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return(c=g.data)==null||c.forEach(h=>{for(const S in h)!isNaN(h[S])&&Number(h[S])!==1/0&&(h[S]=Number(h[S]));const v=y(`${h.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"),I=h.eta?y(`${h.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"):void 0,M=h.status,{labelCn:E,labelEn:q}=this.parseStatus(M),A={mmsi:h.mmsi,imo:n==null?void 0:n.imo,lat:h.lat,lng:h.lon,sog:h.sog,cog:h.cog,hdg:h.hdg,draught:h.draught,status:M,eta:I==null?void 0:I.unix(),destination:h.dest,positionTime:v.unix(),labelCn:E,labelEn:q,method:"trajectory",vendor:"myVessel",utc:v.utc().format()},H=Math.floor(v.diff(f,"minute",!0)/(s||1));H!==p&&(p=H,e.push(A))}),e}}class ot extends Z{constructor(t){super();_(this,"token");this.token=t}async realTimePosition(t,i={}){const o="https://api.hifleet.com/position/position/get/token",n={searchParams:{mmsi:t,usertoken:this.token}},s=await Y.post(o,n).json();D.info("[%s] fetch realtime position from: %s - %j",i.requestId,o,n);const e=s==null?void 0:s.list;if(!e)return D.warn("[%s] fetch realtime position failed: %j",i.requestId,o,s),s;for(const f in e)!isNaN(e[f])&&Number(e[f])!==1/0&&(e[f]=Number(e[f]));e.status=e.sp>3?0:1;const d=e.status,{labelCn:r,labelEn:m}=this.parseStatus(d),g=y(`${e.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:e.m,name:e.n,imo:e.imonumber,callSign:e.callsign,lat:Math.round(e.la/60*1e5)/1e5,lng:Math.round(e.lo/60*1e5)/1e5,length:e.l,width:e.w,draught:e.draught,sog:e.sp,cog:e.co,hdg:e.h,rot:isNaN(e.rot)?0:e.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e.eta)?y(`${e.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00").unix():void 0,destination:e.destination,positionTime:g.unix(),utc:g.utc().format(),status:d,labelCn:r,labelEn:m,method:"position",vendor:"hifleet"}}async search(t,i={}){let o="https://www.hifleet.com/hifleetapi/searchVesselOL.do";const n={searchParams:{keyword:t},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}};let s=await Y.post(o,n).json();D.info("[%s] fetch vessel props from: %s - %j",i.requestId,o,n),s instanceof Array&&(s=s[0]);for(const d in s)!isNaN(s[d])&&Number(s[d])!==1/0&&(s[d]=Number(s[d]));const e={mmsi:s.m,name:s.n,imo:s.i,callSign:s.c,length:s.l,breadth:s.b,draught:s.dr};return o="https://www.hifleet.com/hifleetapi/sameShipSearch.do",s=await Y.post(o,n).json(),D.info("[%s] fetch vessel dead weight from: %s - %j",i.requestId,o,n),s instanceof Array&&(s=s[0]),s&&(e.deadweight=Number(s.dwt)),e}async trajectory(t,i,o,n,s=!0,e={}){var h,v,I;const d=await this.realTimePosition(t,e);let r=y(i);const m=y(o),g=y();if(s){let M=m.diff(r,"d",!0);M<0?r=m.clone().subtract(40,"d"):M<30?r.subtract(10,"d"):M<60?r.subtract(5,"d"):r=m.clone().subtract(80,"d"),M=g.diff(m,"d",!0),m.add(M>10?240:M*24,"h")}const p={searchParams:{endtime:m.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),starttime:r.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),mmsi:t,usertoken:this.token}},f="https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",l=await Y.get(f,p).json();D.info("[%s] fetch trajectory from: %s - %j",e.requestId,f,p);let b;l&&(b=((v=(h=l.ships)==null?void 0:h.offors)==null?void 0:v.ship)||[],b.length||D.warn("[%s] fetch trajectory failed: %j",e.requestId,l));const w=[];let u=-1;const c=y(`${(I=b==null?void 0:b[0])==null?void 0:I.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");for(const M of b){for(const O in M)!isNaN(M[O])&&Number(M[O])!==1/0&&(M[O]=Number(M[O]));const E=y(`${M.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");M.status=M.sp>4?0:1;const{labelEn:q,labelCn:A}=this.parseStatus(M.status),H={mmsi:M.m,name:M.n,imo:d==null?void 0:d.imo,lat:M.la,lng:M.lo,draught:M.draught,sog:M.sp,cog:M.co,hdg:M.hdg,positionTime:E.unix(),utc:E.utc().format(),status:M.status,labelCn:A,labelEn:q,method:"trajectory",vendor:"hifleet"},S=Math.floor(E.diff(c,"minute",!0)/(n||1));S!==u&&(u=S,w.push(H))}return w}}class nt extends Z{constructor(t){super();_(this,"token");this.token=t}async realTimePosition(t,i={}){const o={searchParams:{id:t,k:this.token,enc:1}},n="https://api.shipxy.com/apicall/GetSingleShip",s=await Y.get(n,o).json();if(D.info("[%s] fetch realtime position from: %s - %j",i.requestId,n,o),(s==null?void 0:s.status)!==0)return s;const e=s.data[0];for(const p in e)!isNaN(e[p])&&Number(e[p])!==1/0&&(e[p]=Number(e[p]));const{labelCn:d,labelEn:r}=await this.parseStatus(e.navistat),m=y.unix(e.lasttime);return{mmsi:e.ShipID,name:e.name,imo:e.imo,callSign:e.callsign,lat:Math.round(e.lat/1e6*1e5)/1e5,lng:Math.round(e.lon/1e6*1e5)/1e5,length:Math.round(e.length/10*100)/100,width:Math.round(e.width/10*100)/100,draught:Math.round(e.draught/1e3*100)/100,sog:Math.round(e.sog*3600/1e3/1852*100)/100,cog:Math.round(e.cog/100*100)/100,hdg:Math.round(e.hdg/100*100)/100,rot:Math.round(e.rot/100*100)/100,positionTime:e.lasttime,utc:m.utc().format(),status:e.navistat,labelEn:r,labelCn:d,method:"position",vendor:"shipxy"}}async trajectory(t,i,o,n,s=!0,e={}){var c;const d=await this.realTimePosition(t,e),r=y(i),m=y(o),g="https://api.shipxy.com/apicall/GetShipTrack",p={searchParams:{id:t,k:this.token,enc:1,cut:0,btm:r.unix(),etm:m.unix()}},f=await Y.get(g,p).json();if(D.info("[%s] fetch trajectory from: %s - %j",e.requestId,g,p),(f==null?void 0:f.status)!==0)return f;const l=f==null?void 0:f.points,b=[],w=y.unix((c=l[0])==null?void 0:c.utc);let u=-1;for(const h of l){const v=y.unix(h.utc),I={imo:d==null?void 0:d.imo,mmsi:t,sog:Math.round(h.sog*3600/1e3/1852*100)/100,cog:Math.round(h.cog/100*100)/100,lat:Math.round(h.lat/1e6*1e5)/1e5,lng:Math.round(h.lon/1e6*1e5)/1e5,positionTime:v.unix(),utc:v.utc().format(),method:"trajectory",vendor:"shipxy"},M=Math.floor(v.diff(w,"minute",!0)/(n||1));M!==u&&(u=M,b.push(I))}return b}}class it extends Z{constructor(t){super();_(this,"token");this.token=t}async getShipId(t,i={}){const o={headers:{appKey:this.token},json:{mmsiList:t}},n="https://api3.myships.com/sp/ships/getShipIdByMMSI",s=await Y.post(n,o).json();return D.info("[%s] fetch ship id from: %s - %j",i.requestId,n,o),s.code!=="0"?s:s.data[0].shipId}async getShipInfo(t,i={}){const o={headers:{appKey:this.token},json:{shipId:t}},n="https://api3.myships.com/sp/ships/aissta",s=await Y.post(n,o).json();if(D.info("[%s] fetch ship info from: %s - %j",i.requestId,n,o),s.code!=="0")return s;const e=s.data;let d=e.imo;return t==="407170"&&(d="9198379",D.warn("[%s] ship(%s) imo error: %s, should be %s",i.requestId,t,e.imo,d)),{mmsi:e.mmsi,name:e.shipnameEn,imo:d,callSign:e.callSign,length:e.length,width:e.breadth,draught:(e.draught||100)/10}}async realTimePosition(t,i={}){const o=await this.getShipId(t,i),n=await this.getShipInfo(o,i),s={headers:{appKey:this.token},json:{shipId:o}},e="https://api3.myships.com/sp/ships/position/latest",d=await Y.post(e,s).json();D.info("[%s] fetch realtime position from: %s - %j",i.requestId,e,s);const r=d.data[0];for(const l in r)!isNaN(r[l])&&Number(r[l])!==1/0&&(r[l]=Number(r[l]));const{labelCn:m,labelEn:g}=await this.parseStatus(r.aisNavStatus),p=y.unix(r.posTime);return{...n,mmsi:t,lat:Math.round(r.lat/1e4/60*1e5)/1e5,lng:Math.round(r.lon/1e4/60*1e5)/1e5,sog:Math.round(r.sog/10*100)/100,cog:Math.round(r.cog/10*100)/100,hdg:Math.round(r.heading*100)/100,rot:Math.round(r.rot*100)/100,positionTime:r.posTime,utc:p.utc().format(),status:r.aisNavStatus,labelEn:g,labelCn:m,method:"position",vendor:"myship"}}async trajectory(t,i,o,n,s=!0,e={}){const d=y(i),r=y(o),m=await this.getShipId(t),g=await this.getShipInfo(m),p=[];for(;r.diff(d,"day",!0)>30;)await this.trajectoryIn30Day(m,d.unix(),d.add(30,"day").unix(),g,t,n,p);return await this.trajectoryIn30Day(m,d.unix(),r.unix(),g,t,n,p),p}async trajectoryIn30Day(t,i,o,n,s,e,d,r={}){var w;const m={headers:{appKey:this.token},json:{shipId:t,startTime:i,endTime:o}},g="https://api3.myships.com/sp/ships/position/history",p=await Y.post(g,m).json();if(D.info("[%s] fetch trajectory from: %s - %j",r.requestId,g,m),p.code!=="0")return D.warn("[%s] invoke myship trajectory failed: %j",r.requestId,p),p;const f=p.data;for(const u in f)!isNaN(f[u])&&Number(f[u])!==1/0&&(f[u]=Number(f[u]));const l=y.unix((w=f[0])==null?void 0:w.posTime);let b=-1;for(const u of f){const c=y.unix(u.posTime),h={imo:n==null?void 0:n.imo,mmsi:s,lat:Math.round(u.lat/1e4/60*1e5)/1e5,lng:Math.round(u.lon/1e4/60*1e5)/1e5,sog:Math.round(u.sog/10*100)/100,cog:Math.round(u.cog/10*100)/100,hdg:Math.round(u.heading*100)/100,rot:Math.round(u.rot*100)/100,positionTime:c.unix(),utc:c.utc().format(),method:"trajectory",vendor:"myship"},v=Math.floor(c.diff(l,"minute",!0)/(e||1));v!==b&&(b=v,d.push(h))}return d}}const K=R.getLogger("vessel");var z=(k=>(k.NOTICE="NOTICE",k.WARN="WARN",k.HEAVY="HEAVY",k.SEVERE="SEVERE",k.ERROR="ERROR",k.FATAL="FATAL",k))(z||{});class G{parsePrinciple(a,t={}){var e,d,r;K.info("[%s] parse rule: %s",t.requestId,a);const i=new RegExp("(?<=\\[)(.+)(?=])","g"),o=a.match(i)?(e=a.match(i))==null?void 0:e[0]:void 0,n=o==null?void 0:o.split(";");if(!n)return;const s={};for(let m=0;m<(n==null?void 0:n.length);m++){const g=(r=(d=n[m].match(i))==null?void 0:d[0])==null?void 0:r.split("],");if(m===0&&!g)s.scope=n[0];else if(g)for(let p=0,f=g.length;p<f;p++){const l=this.parseRule(g[p]);l&&(s[l.level]?l.key?s[l.level][l==null?void 0:l.key]=l:s[l.level]=l:l.key?s[l.level]={[l==null?void 0:l.key]:l}:s[l.level]=l)}}return s}parseRule(a,t={}){var s;K.info("[%s] parse rule: %s",t.requestId,a),a=a.startsWith("[")?a:`[${a}`,a=a.endsWith("]")?a:`${a}]`;const i=new RegExp("(?<=\\[)(.+?)(?=])","g"),o=(s=a==null?void 0:a.match(i))==null?void 0:s[0],n=o==null?void 0:o.split(",");if(n)return{operator:n[0],number:Number.isNaN(Number(n[1]))?n[1]:Number(n[1]),level:n[2],time:Number(n[3]),key:n[4]}}checkWeather(a,t,i={}){var l,b,w,u,c,h,v,I,M,E,q,A,H,S,O;let o=0,n=0,s=0,e=0;const d=Math.round(((b=(l=t==null?void 0:t.SEVERE)==null?void 0:l.sigWave)==null?void 0:b.number)*1.6*100)/100,r=(u=(w=t==null?void 0:t.SEVERE)==null?void 0:w.sigWave)==null?void 0:u.number,m=(h=(c=t==null?void 0:t.HEAVY)==null?void 0:c.sigWave)==null?void 0:h.number,g=Math.round((((I=(v=t==null?void 0:t.SEVERE)==null?void 0:v.wind)==null?void 0:I.number)+2)*100)/100,p=(E=(M=t==null?void 0:t.SEVERE)==null?void 0:M.wind)==null?void 0:E.number,f=(A=(q=t==null?void 0:t.HEAVY)==null?void 0:q.wind)==null?void 0:A.number;for(let W=0;W<(a==null?void 0:a.length);W++){const T=a[W],L=(S=(H=T==null?void 0:T.meteo)==null?void 0:H.wave)==null?void 0:S.sig,C=(O=T==null?void 0:T.meteo)==null?void 0:O.wind,V=W?y(T.eta).diff(y(a[W-1].eta),"hour",!0):0;e=V>e?V:e,K.info("[%s] check sig.wave: %j",i.requestId,{...L,dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:m}),(L==null?void 0:L.height)>=d?T.isDangerous=!0:(L==null?void 0:L.height)>=r?T.isSevere=!0:(L==null?void 0:L.height)>=m&&(T.isHeavy=!0),K.info("[%s] check wind: %j",i.requestId,{...C,dgThd4Wd:g,svThd4Wd:p,hvThd4Wd:f}),(C==null?void 0:C.scale)>=g?(T.isDangerous=!0,delete T.isSevere,delete T.isHeavy):(C==null?void 0:C.scale)>p?(T.isDangerous||(T.isSevere=!0),delete T.isHeavy):(C==null?void 0:C.scale)===f&&!T.isDangerous&&!T.isSevere&&(T.isHeavy=!0),o+=T.isDangerous?V:0,n+=T.isSevere?V:0,s+=T.isHeavy?V:0}return o=Math.round(o*100)/100,n=Math.round(n*100)/100,s=Math.round(s*100)/100,e=Math.round(e),{sample:a,dangerous:o,severe:n,heavy:s,step:e<3?3:e,wind:{dgThd4Wd:g,svThd4Wd:p,hvThd4Wd:f},sig:{dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:m}}}}const rt=new G,B=R.getLogger("vessel");var U=(k=>(k.common="common",k.container="container",k))(U||{}),J=(k=>(k.Ballast="Ballast",k.Laden="Laden",k))(J||{}),Q=(k=>(k.Cp="CP",k.Perf="Basis",k.Instruct="Other",k))(Q||{});class F{static blockCoefficient(a,t,i,o){let n=Math.round(a/(t*i*o)*100)/100;n=n<.55?.55:n>.85?.85:n;const s=[.55,.6,.65,.7,.75,.8,.85],e=s.map(d=>Math.abs(d-n));return s[e.indexOf(Math.min(...e))]}static froudeNumber(a,t,i=9.8){let o=Math.round(Math.sqrt(a*a/(i*t))*100)/100;return o=o<.05?.05:o>.3?.3:o,o}static amendFactor(a,t,i){const o={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.4,-10.6,-9.5],.8:[2.6,-13.1,-15.1],.85:[3.1,-18.7,28]};let s={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.6,-12.5,-13.5],.8:[3,-16.3,-21.6],.85:[3.4,-20.9,31.8]}[a];return i==="Laden"&&(s=o[a]),s[0]+s[1]*t+s[2]*Math.pow(t,2)}static directionFactor(a,t=0){let i;return a>30&&a<=60?i=(1.7-.03*Math.pow(t-4,2))/2:a>60&&a<=150?i=(.9-.06*Math.pow(t-6,2))/2:i=(.4-.03*Math.pow(t-8,2))/2,Math.round(i*1e5)/1e5}static vesselTagFactor(a,t,i,o=0){o=o>5?o-.9*(o-5):o;let n;return i==="container"?n=.7*o+Math.pow(o,6.5)/(22*Math.pow(a,2/3)):t==="Ballast"?n=.7*o+Math.pow(o,6.5)/(2.7*Math.pow(a,2/3)):n=.5*o+Math.pow(o,6.5)/(2.7*Math.pow(a,2/3)),n}static waveHeightFactor(a){return a=a<1.25?1.25:a,a=a>6?a-.9*(a-6):a,Math.round((-.144*Math.pow(a,2)+.178*a)*1e4)/1e4}static assembleProperties(a,t,i,o){var m,g;const n=a.lbp??a.length??a.lengthOverall??198.9642,s=a.draught??8,e=a.breadthMoulded??a.breadth??a.breadthExtreme??32.4572,d=a.deadweight??67035.7773;return{tag:((g=(m=a==null?void 0:a.type)==null?void 0:m.toLowerCase())==null?void 0:g.indexOf("container"))>-1?"container":"common",lbp:n,loadCondition:t,draught:s,breadthMoulded:e,displacement:Math.round((d/1.025+s*e*n*.7)*1e4)/1e4,speed:Math.round((i??14.1382)*1852/3600*1e4)/1e4,bearing:o||90}}static async speedLoseAt(a,t,i,o="",n=2,s=!1,e={}){t.velocity&&!t.noFactor&&s&&(a.speed=x.LngLatHelper.roundPrecision(t.velocity*1852/3600,6));const d=await st.MeteoHelper.queryPointFactor(t.lng,t.lat,i.valueOf(),"wind,wave,current,watertemp",o,e),r=F.weatherFactor(a,d),m=F.currentFactor(a.bearing,d==null?void 0:d.current,n),g={meteo:{...d},wxFactor:r,cFactor:m,speed:t.velocity&&s?t.velocity:Math.round((a.speed*1.943844+r+m)*100)/100,eta:i.utc().format("YYYY-MM-DDTHH:mm[Z]"),etd:i.utc().format("YYYY-MM-DDTHH:mm[Z]")};return delete t.meteo,delete t.wxFactor,delete t.cFactor,delete t.speed,delete t.etd,{...g,...t}}static async speedLoseInHoursStep(a,t,i,o,n,s,e="",d=!1,r={}){t.utc();const m=[],g=[];let p=0,f=0,l,b;for(let w=0;w<s.length-1;w++){let u=s[w];u.distanceFromStart=n+f;const c=s[w+1];if(a.bearing=x.LaneHelper.calculateBearing(u,c,!c.gcToPrevious),u.bearing=a.bearing,u.suspend&&d){u.eta=u.eta||t.format("YYYY-MM-DDTHH:mm[Z]"),u.elapsed=u.elapsed??0;const I=u.suspend-u.elapsed;if(o-p>I)o=o-p-I,t.add(I,"hour"),u.elapsed=u.suspend;else{const M=o-p;u.elapsed+=M,t.add(M,"hour"),o=0}if(B.info(`[%s] suspend ${u.elapsed} hours at %j, and remain ${o} hours need to go...`,r.requestId,u),o===0)return u.distanceFromPrevious=f,{etd:t,from:b||u,to:u,next:s.filter(M=>M),wps:m,days:g}}u=await F.speedLoseAt(a,u,t,e,0,d,r),b=b||u,u.important&&m.push(u),t.isSameOrAfter(i)&&(g.push(u),i.add(24,"hour"));const h=x.LaneHelper.calculateDistance(u,c,!c.gcToPrevious);let v=Math.ceil(h/b.speed*1e4)/1e4;if(p+v<o){if(p+=v,t.add(v,"hour"),delete s[w],B.info(`[%s] go to %j from %j with ${h}nm, and cost ${v} hours`,r.requestId,{lat:c.lat,lng:c.lng},{lat:b.lat,lng:b.lng,etd:b.etd}),f+=h,s.filter(I=>I).length<=1){l=c,l.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),l.distanceFromPrevious=h,l.distanceFromStart=n+f,m.push(l),delete s[w+1];break}}else{v=o-p,t.add(v,"hour");const I=x.LngLatHelper.roundPrecision(b.speed*v,4);l=x.LaneHelper.calculateCoordinate(u,a.bearing,I,"nauticalmiles",!c.gcToPrevious),l.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),s[w]=l,B.info(`[%s] go to %j from %j with ${I}nm, and cost ${v} hours`,r.requestId,{lat:l.lat,lng:l.lng},{lat:u.lat,lng:u.lng,etd:u.etd}),f+=I,l.distanceFromPrevious=f,l.distanceFromStart=n+f;break}}return{etd:t,from:b,to:l,next:s.filter(w=>w),wps:m,days:g}}static currentFactor(a,t,i=0){const o=(a-(t==null?void 0:t.degree)||0)/180*Math.PI;if(Math.abs(o)===Math.PI/2)return 0;let n=((t==null?void 0:t.kts)||0)*Math.cos(o);return i&2?n=Math.ceil(n*100)/100:i&1?n=Math.floor(n*100)/100:n=Math.round(n*100)/100,Math.abs(n)>5?0:n}static weatherFactor(a,t){var g,p,f,l,b;B.debug("calculate weather factor via: %j",{...a,...t});const i=F.blockCoefficient(a.displacement,a.lbp,a.breadthMoulded,a.draught),o=F.froudeNumber(a.speed,a.lbp),n=F.amendFactor(i,o,a.loadCondition);let s=Math.abs(a.bearing%360-(((g=t==null?void 0:t.wind)==null?void 0:g.degree)%360||0));s=s>180?360-s:s;const e=F.directionFactor(s,(p=t==null?void 0:t.wind)==null?void 0:p.scale),d=F.vesselTagFactor(a.displacement,a.loadCondition,a.tag,(f=t==null?void 0:t.wind)==null?void 0:f.scale);let r=e*n*d/100*a.speed;r=Math.round(r*1.943844*1e4)/1e4*-1;const m=F.waveHeightFactor(((b=(l=t==null?void 0:t.wave)==null?void 0:l.sig)==null?void 0:b.height)??1);return r=r*.24+m*.76,B.debug("weather factor = %s",r),Math.round(r*100)/100}static async analyseInstant(a,t,i,o,n,s="",e=0,d=!1,r={}){var L,C,V,X,tt;const m=y().valueOf();a.lng=x.LngLatHelper.convertToStdLng(a.lng);const{route:g,waypoints:p}=n.points,f=x.LaneHelper.calculateSubRoute(a,g);if(((L=f[0])==null?void 0:L.length)<=1)return;const{v0:l,label:b}=a.sog?{v0:a.sog,label:"Other"}:{v0:o.speed,label:"CP"},w=F.assembleProperties(i,o.loadCondition,l,0),u=p.length?x.LaneHelper.calculateSubWaypoints(a,p):[],c={from:{...a},route:f,waypoints:u,v0:l,label:b},h={hours:[],days:[],wps:[]};e||(x.LaneHelper.calculateRouteDistance(f)/o.speed<=72?e=3:e=6);let v=x.LaneHelper.simplifyRouteToCoordinates(f,u,0),I=0,M=0,E=0,q=0;t=y(t).utc();const A=t.clone();for(;v.length>0;){const P=e-t.hour()%e,$=Math.ceil(t.clone().add(P,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4,N=await F.speedLoseInHoursStep(w,t,A,$,I,v,s,d,r);(C=N.from)!=null&&C.speed&&(h.hours.push(N.from),h.wps.push(...N.wps),h.days.push(...N.days)),v=N==null?void 0:N.next,v.length||h.hours.push(N==null?void 0:N.to),I+=((V=N==null?void 0:N.to)==null?void 0:V.distanceFromPrevious)??0}const H=h.hours;for(let P=0;P<H.length-1;P++){const $=y(H[P+1].eta).diff(H[P].etd,"hour",!0)||1;M+=H[P].wxFactor*$,E+=H[P].cFactor*$,q+=$}(X=h.wps)==null||X.forEach((P,$)=>{if($){const N=h.wps[$-1],ct=P.distanceFromStart-N.distanceFromStart,et=y(P.eta).diff(y(N.etd),"h",!0);et<1?P.avgSpd=N.speed:P.avgSpd=Math.round(ct/et*100)/100}}),c.sample=h;const S=h.hours.at(-1);c.distance=Math.round(S.distanceFromStart*1e4)/1e4,c.eta=y(S.eta).toDate(),c.wxFactor=Math.round(M/q*1e4)/1e4,c.cFactor=Math.round(E/q*1e4)/1e4,c.avgSpeed=Math.round(S.distanceFromStart/q*1e4)/1e4,c.totalHrs=Math.round(q*1e4)/1e4,c.totalFoCons=Math.round((o==null?void 0:o.fo)/24*c.totalHrs*1e3)/1e3,c.totalDgoCons=Math.round((o==null?void 0:o.dgo)/24*c.totalHrs*1e3)/1e3;const W=y().valueOf()-m,T=((tt=h==null?void 0:h.hours)==null?void 0:tt.length)||1;return B.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms",r==null?void 0:r.requestId,W,T,Math.round(W/T*1e3)/1e3),c}static async analyseInstantWithThreshed(a,t,i,o,n,s,e="",d=3,r=!1,m={}){var E,q,A;a.lng=x.LngLatHelper.convertToStdLng(a.lng);const g=F.assembleProperties(o,n.loadCondition,n.speed,0),p=x.LaneHelper.calculateSubRoute(a,s);if(((E=p[0])==null?void 0:E.length)<=1)return;let f=x.LaneHelper.simplifyRouteToCoordinates(p,[],0);f.forEach(H=>H.important=!0);let l=0,b=0,w=0,u=0,c;const h={hours:[],wps:[],days:[]};for(t=y(t).utc();f.length>0;){const H=d-t.hour()%d;let S=Math.ceil(t.clone().add(H,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4;if(S=t.clone().add(S,"h").isAfter(i)?i.diff(t,"h",!0)*1e4/1e4:S,S)c=await F.speedLoseInHoursStep(g,t,i.clone(),S,l,f,e,r,m),(q=c.from)!=null&&q.speed&&(h.hours.push(c.from),c!=null&&c.wps&&h.wps.push(...c.wps),h.days.push(...c.days)),f=c==null?void 0:c.next,f.length||(h.hours.push(c==null?void 0:c.to),c!=null&&c.wps&&h.wps.push(...c.wps),h.days.push(c==null?void 0:c.to)),l+=((A=c==null?void 0:c.to)==null?void 0:A.distanceFromPrevious)??0;else{c&&(h.hours.push(c.to),c!=null&&c.wps&&h.wps.push(...c.wps),h.days.push(c.to));break}}const v=h.hours;for(let H=0;H<v.length-1;H++){const S=y(v[H+1].eta).diff(v[H].etd,"hour",!0);b+=v[H].wxFactor*S,w+=v[H].cFactor*S,u+=S}const I=h.hours.at(-1);return{sample:h,distance:Math.round(((I==null?void 0:I.distanceFromStart)||0)*1e4)/1e4,eta:y(I==null?void 0:I.eta).utc().format(),wxFactor:Math.round(b/u*1e4)/1e4,cFactor:Math.round(w/u*1e4)/1e4,avgSpeed:Math.round(((I==null?void 0:I.distanceFromStart)||0)/u*1e4)/1e4,totalHrs:Math.round(u*1e4)/1e4,to:I,route:x.LaneHelper.generateRouteAccordingToWaypoints(f)}}}j.AISImpl=Z,j.AlertHelper=G,j.AlertLevel=z,j.HifleetImpl=ot,j.LoadCondition=J,j.MyShipImpl=it,j.MyVesselImpl=at,j.ShipxyImpl=nt,j.SpeedHelper=F,j.SpeedLabel=Q,j.VesselTag=U,j.alertHelper=rt,Object.defineProperty(j,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { Current, Meteo } from '@idm-plugin/meteo';
|
|
2
|
+
import moment from 'moment';
|
|
3
|
+
/**
|
|
4
|
+
* 船舶标签,不同标签适用不同分析模型
|
|
5
|
+
*/
|
|
6
|
+
export declare enum VesselTag {
|
|
7
|
+
common = "common",
|
|
8
|
+
container = "container"
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 船舶加载状态,laden/ ballast
|
|
12
|
+
*/
|
|
13
|
+
export declare enum LoadCondition {
|
|
14
|
+
Ballast = "Ballast",
|
|
15
|
+
Laden = "Laden"
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 速度标签
|
|
19
|
+
*/
|
|
20
|
+
export declare enum SpeedLabel {
|
|
21
|
+
Cp = "CP",
|
|
22
|
+
Perf = "Basis",
|
|
23
|
+
Instruct = "Other"
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 船舶基础档案
|
|
27
|
+
*/
|
|
28
|
+
export interface VesselAssemble {
|
|
29
|
+
imo?: number;
|
|
30
|
+
lbp?: number;
|
|
31
|
+
length?: number;
|
|
32
|
+
lengthOverall?: number;
|
|
33
|
+
draught?: number;
|
|
34
|
+
breadthMoulded?: number;
|
|
35
|
+
breadth?: number;
|
|
36
|
+
breadthExtreme?: number;
|
|
37
|
+
type?: string;
|
|
38
|
+
deadweight: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 船舶运行参数,用于分析船舶失速、油耗、性能、碳排等
|
|
42
|
+
*/
|
|
43
|
+
export interface VesselProperties {
|
|
44
|
+
tag: VesselTag;
|
|
45
|
+
loadCondition: LoadCondition | string;
|
|
46
|
+
draught: number;
|
|
47
|
+
displacement: number;
|
|
48
|
+
breadthMoulded: number;
|
|
49
|
+
lbp: number;
|
|
50
|
+
speed: number;
|
|
51
|
+
bearing: number;
|
|
52
|
+
}
|
|
53
|
+
export declare class SpeedHelper {
|
|
54
|
+
/**
|
|
55
|
+
* @see https://baike.baidu.com/item/%E6%96%B9%E5%BD%A2%E7%B3%BB%E6%95%B0/4965568?fr=aladdin
|
|
56
|
+
* 方形系数(block coefficient)
|
|
57
|
+
* 是指与基平面相平行的任一水线面以下的船型排水体积与对应的船长、型宽
|
|
58
|
+
* 和平均吃水的乘积所表示的长方体体积之比
|
|
59
|
+
* 方块系数介于 0.55 - 0.85
|
|
60
|
+
* @param displacement 排水 m^3
|
|
61
|
+
* @param length 水线长 m
|
|
62
|
+
* @param breadth 水线宽 m
|
|
63
|
+
* @param draught 吃水 m
|
|
64
|
+
* @return [0.55, 0.85]
|
|
65
|
+
*/
|
|
66
|
+
private static blockCoefficient;
|
|
67
|
+
/**
|
|
68
|
+
* @see https://baike.baidu.com/item/%E5%BC%97%E5%8A%B3%E5%BE%B7%E6%95%B0/228891?fromModule=search-result_lemma-recommend
|
|
69
|
+
* 弗劳德数 (froude number)
|
|
70
|
+
* 流体力学中表征流体惯性力和重力相对大小的一个无量纲参数,记为Fr。它表示惯性力和重力量级的比,即:Fr=sqrt(U²/(gL)) [6] ,
|
|
71
|
+
* 式中U为物体运动速度,g为重力加速度;L为物体的特征长度
|
|
72
|
+
* 佛勞德數介乎 0.05 - 0.30
|
|
73
|
+
* @param speed 速度 m/s
|
|
74
|
+
* @param length 船长 m
|
|
75
|
+
* @param g 重力加速度 9.80 m/s^2
|
|
76
|
+
* @return [0.05, 0.30]
|
|
77
|
+
*/
|
|
78
|
+
private static froudeNumber;
|
|
79
|
+
/**
|
|
80
|
+
* 失速修正系數
|
|
81
|
+
* @param bc 方形系数 [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85]
|
|
82
|
+
* @param fr 弗劳德数 [0.05 - 0.30]
|
|
83
|
+
* @param loadCondition
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
private static amendFactor;
|
|
87
|
+
/**
|
|
88
|
+
* 失速方向因子
|
|
89
|
+
* 頂浪(不規則 波)、頂風 (0°): 2 * 𝐶𝜇 = 2
|
|
90
|
+
* 艏斜浪(不規 則波)、前迎風 (30°~60°): 2 𝐶𝜇 = 1.7 −0.03(Bn − 4)^2
|
|
91
|
+
* 橫浪(不規則 波)、橫風 (60°~150°): 2 𝐶𝜇 = 0.9 −0.06(Bn − 6)^2
|
|
92
|
+
* 順浪(不規則 波)、順風 (150°~180°): 2 𝐶𝜇 = 0.4 −0.03(Bn− 8)^2
|
|
93
|
+
*
|
|
94
|
+
* @param beta 航向与风浪的夹角
|
|
95
|
+
* @param bn
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
98
|
+
private static directionFactor;
|
|
99
|
+
/**
|
|
100
|
+
* 失速船型因子
|
|
101
|
+
* 集装箱(普通裝載狀態): 0.7Bn + Bn^6.5/(22 * ∇^(2/3))
|
|
102
|
+
* 散货等(满载): 0.5Bn + Bn^6.5 2 /(2.7 * ∇^(2/3))
|
|
103
|
+
* 散货等(压载): 0.7Bn + Bn^6.5 2 /(2.7 * ∇^(2/3))
|
|
104
|
+
* @param displacement 排水量,m^3
|
|
105
|
+
* @param loadCondition
|
|
106
|
+
* @param tag
|
|
107
|
+
* @param bn
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
private static vesselTagFactor;
|
|
111
|
+
/**
|
|
112
|
+
* 浪高影响因子
|
|
113
|
+
* @param ht 浪高,单位m
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
private static waveHeightFactor;
|
|
117
|
+
/**
|
|
118
|
+
* 组装船舶运行参数
|
|
119
|
+
* @param vessel 船舶基础档案
|
|
120
|
+
* @param loadCondition 装载状态
|
|
121
|
+
* @param speed 速度,kts
|
|
122
|
+
* @param bearing 方位角
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
private static assembleProperties;
|
|
126
|
+
/**
|
|
127
|
+
* 船舶特定时间的瞬时失速样本
|
|
128
|
+
* @param props 船舶属性
|
|
129
|
+
* @param coordinate {lat: 纬度, lng: 经度, velocity: 速度(kts, 可选,指定速度) }
|
|
130
|
+
* @param eta 位置时间
|
|
131
|
+
* @param source [CMEMS, GFS, Other]
|
|
132
|
+
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
133
|
+
* @param useRouteParam true 启用设置速度
|
|
134
|
+
*/
|
|
135
|
+
private static speedLoseAt;
|
|
136
|
+
/**
|
|
137
|
+
* 基于步长计算失速样本
|
|
138
|
+
* @param props 船舶属性(失速模型依赖)
|
|
139
|
+
* @param etd 出发时间
|
|
140
|
+
* @param etd4Day 前行过程中动态计算加24小时的天(etd + 24 * n)
|
|
141
|
+
* @param hours 前行的步长(小时)
|
|
142
|
+
* @param distanceFromStart 与最开始起点的距离
|
|
143
|
+
* @param keypoints 剩下的航路点
|
|
144
|
+
* @param source 气象数据源: CMEMS / GFS
|
|
145
|
+
* @param useRouteParam true 启用航线上设置的参数 { suspend: 停留时长(小时), velocity: 速度(kts)}
|
|
146
|
+
* @private
|
|
147
|
+
*/
|
|
148
|
+
private static speedLoseInHoursStep;
|
|
149
|
+
/**
|
|
150
|
+
* 洋流影响因子
|
|
151
|
+
* @param bearing 船舶航行方位角
|
|
152
|
+
* @param current 洋流要素
|
|
153
|
+
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
154
|
+
*/
|
|
155
|
+
static currentFactor(bearing: number, current: Current, role?: number): number;
|
|
156
|
+
/**
|
|
157
|
+
* 风浪影响因子
|
|
158
|
+
* @param props 船舶档案
|
|
159
|
+
* @param wwc 气象要素
|
|
160
|
+
*/
|
|
161
|
+
static weatherFactor(props: VesselProperties, wwc: Meteo): number;
|
|
162
|
+
/**
|
|
163
|
+
* 全程失速分析(走完航程)
|
|
164
|
+
* @param from 起点 {lng, lat}
|
|
165
|
+
* @param etd 出发时间,YYYY-MM-DDTHH:mm:ssZ
|
|
166
|
+
* @param vessel 船舶属性 @see VesselAssemble, 注意吃水为船舶实时吃水,非档案中的固定吃水,一般可以从ais获取; 如获取不得,用档案吃水代替
|
|
167
|
+
* @param cp { loadCondition, speed } LoadCondition: Ballast or Laden, speed(kts)
|
|
168
|
+
* @param lane 航线 { points: { route, waypoints }}
|
|
169
|
+
* @param source 气象数据源,GFS or CMEMES, 默认CMEMS
|
|
170
|
+
* @param stepHrs 样本步长, 0表示动态计算(6 or 3 hrs)
|
|
171
|
+
* @param useRouteParam
|
|
172
|
+
*/
|
|
173
|
+
static analyseInstant(from: any, etd: any, vessel: VesselAssemble, cp: {
|
|
174
|
+
loadCondition: string;
|
|
175
|
+
speed: number;
|
|
176
|
+
fo: number;
|
|
177
|
+
dgo: number;
|
|
178
|
+
}, lane: {
|
|
179
|
+
points: {
|
|
180
|
+
route: number[][][];
|
|
181
|
+
waypoints: any[];
|
|
182
|
+
};
|
|
183
|
+
voyage: any;
|
|
184
|
+
}, source?: string, stepHrs?: number, useRouteParam?: boolean, options?: {
|
|
185
|
+
requestId?: string;
|
|
186
|
+
}): Promise<any>;
|
|
187
|
+
/**
|
|
188
|
+
* 分段失速分析(最多走hours 小时)
|
|
189
|
+
* @param from 起点 {lng, lat}
|
|
190
|
+
* @param etd 出发时间,YYYY-MM-DDTHH:mm:ssZ
|
|
191
|
+
* @param threshed 单次所走上限时间
|
|
192
|
+
* @param vessel 船舶属性 @see VesselAssemble, 注意吃水为船舶实时吃水,非档案中的固定吃水,一般可以从ais获取; 如获取不得,用档案吃水代替
|
|
193
|
+
* @param cp { loadCondition, speed } LoadCondition: Ballast or Laden, speed(kts)
|
|
194
|
+
* @param route 航路[[[lng, lat]]]
|
|
195
|
+
* @param source 气象数据源,GFS or CMEMES, 默认CMEMS
|
|
196
|
+
* @param stepHrs
|
|
197
|
+
*/
|
|
198
|
+
static analyseInstantWithThreshed(from: any, etd: any, threshed: moment.Moment, vessel: VesselAssemble, cp: {
|
|
199
|
+
loadCondition: string;
|
|
200
|
+
speed: number;
|
|
201
|
+
fo: number;
|
|
202
|
+
dgo: number;
|
|
203
|
+
}, route: number[][][], source?: string, stepHrs?: number, useRouteParam?: boolean, options?: {
|
|
204
|
+
requestId?: string;
|
|
205
|
+
}): Promise<{
|
|
206
|
+
sample: any;
|
|
207
|
+
distance: number;
|
|
208
|
+
eta: string;
|
|
209
|
+
wxFactor: number;
|
|
210
|
+
cFactor: number;
|
|
211
|
+
avgSpeed: number;
|
|
212
|
+
totalHrs: number;
|
|
213
|
+
to: any;
|
|
214
|
+
route: any;
|
|
215
|
+
} | undefined>;
|
|
216
|
+
}
|