@gml/truewind
Version:
Modern ES6+ library for apparent to true wind calculation in sailing applications.
2 lines (1 loc) • 2.76 kB
JavaScript
!function(t,a){"object"==typeof exports&&"undefined"!=typeof module?a(exports):"function"==typeof define&&define.amd?define(["exports"],a):a((t="undefined"!=typeof globalThis?globalThis:t||self).TrueWind={})}(this,(function(t){"use strict";const a=Math.PI/180,o=180/Math.PI;class e{static getTrue(t){const e={...t};if(void 0===e.variation&&(e.variation=0),void 0===e.bspd&&void 0!==e.sog?e.bspd=e.sog:void 0===e.sog&&void 0!==e.bspd&&(e.sog=e.bspd),void 0===e.heading&&void 0!==e.cog?e.heading=e.cog:void 0===e.cog&&void 0!==e.heading&&(e.cog=e.heading),void 0===e.awa&&void 0!==e.awd){for(e.awa=e.awd-(e.heading+e.variation);e.awa>180;)e.awa-=360;for(;e.awa<-180;)e.awa+=360}if(void 0===e.awa||void 0===e.aws||void 0===e.heading||void 0===e.bspd)throw new Error("Please supply at least the parameters { awa, aws, heading, bspd }");let i;if(e.awa>180?e.awa-=360:e.awa<-180&&(e.awa+=360),Object.assign(e,this.getAttitudeCorrections(e)),!e.bspd||!e.roll||!e.K||e.roll>0&&e.awa>0||e.roll<0&&e.awa<0)i=0;else{const t=1.94384*e.bspd;i=e.K*e.roll/(t*t),i>45?i=45:i<-45&&(i=-45)}const s=e.bspd/Math.cos(i*a),r=s*Math.sin(i*a),h=(270-e.awa)*a,n=e.aws*Math.cos(h)+r,d=e.aws*Math.sin(h)+e.bspd,w=Math.sqrt(n*n+d*d),l=Math.atan2(d,n);let g;Number.isNaN(l)?g=d<0?180:0:(g=270-l*o,e.awa>=0?g%=360:g-=360,g>180?g-=360:g<-180&&(g+=360));const c=s*Math.cos((-g+i)*a);let M=e.heading+g;M>360?M-=360:M<0&&(M+=360);const p=e.cog-e.variation,f=(90-(e.heading+i))*a,u=(90-p)*a,v=e.sog*Math.cos(u)-s*Math.cos(f),b=e.sog*Math.sin(u)-s*Math.sin(f),m=Math.sqrt(v*v+b*b),y=Math.atan2(b,v);let C;Number.isNaN(y)?C=b<0?180:0:(C=90-y*o,C>360?C-=360:C<0&&(C+=360));let N=w;if(e.sensorHeight&&e.heightCorrectionMethod){const t={toHeight:10,method:e.heightCorrectionMethod};"log"===e.heightCorrectionMethod?t.z0=.005:"power"===e.heightCorrectionMethod&&(t.alpha=.11),N=function(t,a,o={}){const{toHeight:e=10,method:i="log",z0:s=.005,alpha:r=.11}=o;if(a<=0||e<=0)throw new Error("heights must be > 0 meters");if("log"===i&&(s<=0||s>=Math.min(a,e)))throw new Error("For log-law, z0 must be > 0 and < both heights");let h;if("log"===i)h=t*(Math.log(e/s)/Math.log(a/s));else{if("power"!==i)throw new Error('method must be "log" or "power"');h=t*Math.pow(e/a,r)}return h}(w,e.sensorHeight,t)}return{awa:e.awa,aws:e.aws,leeway:i,stw:s,vmg:c,tws:N,twa:g,twd:M+e.variation,soc:m,doc:C+e.variation}}static getAttitudeCorrections(t){const{roll:e,pitch:i}=t;if(void 0===e||void 0===i)return t;let s=t.awa;s<0&&(s+=360);const r=s,h=t.aws,n=h*Math.sin(r*a),d=h*Math.cos(r*a),w=n/Math.cos(e*a),l=d/Math.cos(i*a);let g=Math.sqrt(w**2+l**2);0!==w&&0!==l||(g=h);let c=Math.atan2(w,l)*o;return c<0&&(c+=360),{...t,aws:g,awa:c}}}t.TrueWind=e,t.default=e,Object.defineProperty(t,"__esModule",{value:!0})}));