From 5b7bf63909b37c5b42f9a92068fbb2fd7c6db716 Mon Sep 17 00:00:00 2001 From: PeekabooSteam Date: Wed, 15 Feb 2023 11:28:14 +0000 Subject: [PATCH] More AIC work so I don't lose it. (Best commit message ever.) --- client/package.json | 2 +- client/public/images/formations/range.png | Bin 2370 -> 5057 bytes client/public/stylesheets/layout.css | 160 +++++++++++++++++++-- client/src/aic/aic.ts | 162 +++++++++++++++++++--- client/src/index.ts | 80 ++++------- client/src/other/utils.ts | 87 +++++++----- client/views/aiccontrolpanel.ejs | 16 ++- client/views/aicformationpanel.ejs | 36 ++++- 8 files changed, 411 insertions(+), 132 deletions(-) diff --git a/client/package.json b/client/package.json index f96322ca..80775352 100644 --- a/client/package.json +++ b/client/package.json @@ -5,8 +5,8 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon ./bin/www\"", "copy": "copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet.css", + "start": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon ./bin/www\"", "watch": "watchify .\\src\\index.ts --debug -p [ tsify --noImplicitAny ] -o .\\public\\javascripts\\bundle.js" }, "dependencies": { diff --git a/client/public/images/formations/range.png b/client/public/images/formations/range.png index fdcf8b0d17b96d6b6be8cd13d5da00bd1bcc7012..9df137cb0eb556708b0a3841ff25c225470fefe6 100644 GIT binary patch delta 4429 zcmbVPc{r5&+qY)R5))GjMYb$W95Re$kg-cb6AojL-O-FG;;}?wY{^N<(ix1MF~6Z^ zD#{qiT6Q($NEtG;ptAj*Iq!R2@9&@Yy58%3{=C2U_r5>(@_g?5`$G1)M!r3N9K}JK zzp#`aTNuf&WfSA<40nwU4GE13h_Hzc#7722;p}Y?$FD}l=wU;#aAR07*1*`{4U&dL5eQ(*vIU>ZIJ@`4vw1YBKZqbpnGtFly*zcr1!odw6u#{jk*imLmfSnzmE-qy6^UBIY z)nq;T-K3OfeCWl&$?0k2?|ii0Pv1K57G`EP1U_28#P?ZxJGyaowu5AsT!&+@=jQ`Q zeqGU#wIsOrv#YDf_`ANl`WLeo<6M$Anc^78WA429jbxvuVR zTU;wCbITV9A|x$4m_^6Um!Iab$?ACHu^Z09(Rk1x~EkA0%l*g2Q998Tp=O-72OSw#_Mw!jrfiQvtd1TI>Z;dChC_rKF+^i6#F&O{)rlaq?tBT2k zxtt|FQW@n643e#-a2<3yfW#2xCiq#kwOTi(OJ4*}7ddnXvQ4}MJ7W~nLpnOz+A`c2 z=YNz-n2hXv_#l)CbMg7dPdf@>ZoXl=8P(2s`ZP!HBl8?Y>0ulJOn*)&Cz}V*rTD>v z4;?+JZVXe|Orbq})A60JUu834NoQ6osIyie^lnUn7{DR@qx}B5xpvH@)3uZ($d4LR z*}&YEoENI2Tq*Tqd&kF~a#2K+7e?ZFpe+og_yW1pjxDLiI&yj|I|WF0V}$?e{+>Dv zmXEyu$&Ib=M>UUX7C9&=DDZP;me*VS@yt#!_?8%Qg&RXI=g<+KVIS`RQ5`Cy=C6(e zW7^dU`CKnAuX|4We20dZOy-Lhsq1z(rhN-hYP+@P-!r)THlSAq-@WtMd##0BA;mCU ztYpBFe1x2Yrh&e-iySE4kO~m9o@hF9b>^vcP2wHfCErVyzv>w&%;GCDVaf$S7Du=a zR8c|Q?gfhosb>V?x)Y<9sa;h!d5df#k2p#{zjt zN{&`5w0F&&uL5((Z-F9@L~t!#2x=_8DcibDx*`Bdn?q^nh;d7g&AvXziHlgisIH4- zOCop2)^MNL)%5nCkX3w-QefxF*vCFJ^!i%zrkO=|9AjXn0HoEP%aR{P$gVqk-e@#3 zTFC7Dshu;9YOK!182J&o=B=MUA4ghw@ny*6oc*~Bxitzh;=?RC=mCqUuoCmqlXdPu z>baMnzAeOFJj`BRr;j{s=UV8_7iN>1 zBH=TtCDY89TbJ{%5bVah?#Q8UkAV$fi7hyMgV#`3l|cS zw|bo~iJgdecBnJl@`6LB^<%(iBcV#+1}`~E0+SAKQIL!T&9X{Prm1+=#w*zlu?_{mY zF3v=?%Vi2>9P*aiR4Fk?1JY5%6mt#^{ysHF0H+TT2f@xy1dsE#Yg!VFyt+~k8kRV_ zW^v9r zt*N9w;d-Jt}@cOPgN);DJz!s=7?~?yh)-9GRC>wpva}w*h8M5=rz|D`q_Z&v+9_aOdQqL--$!}9$?*rgYU=Ax zE^=kvznt@z_#&b{ir1IV26d42W3LushuH|w6?3Bb_snLR)34H72o~1rhkSn9JJM`s z&e=5GWF?Cvrw`XXJw1(#jF@Fz{r&wtdCK;ZawV+c@;HYWJh_bz?dy9~Sy{m(xVm>R zWg2S#CErGhZGVErTLXaq-UGljApdZM3t6?UxGa@^-jVne*xP-cCW5>lywW-@rsv*0 zuI1)HNb|--{O9;TYxf7cZ{c)pbdSyP0=qmV;eSTEW8~$@M=h^YxHACejmf?LocfND zK5Fr&ju&!!dU`6$FgF0?Lk@@2c|YOj*Aw9d(-orn)#L{5N?gfHqq#&Di{a0KS-rXs4rOs15 zFH70gdZcobtWLpZJw&_`2TGt(@h0rkZhdC~Bc`(Acs~cM&G9l{~ z`PRE01(yh~${Y3mTEkkeBrdJPpO5dfWSa?e`sPNFDUfJ?;_LXiY(ZTv z7a(F!+i$#!Ag$f8UKtn2jDR7I;>q`*%YlmjxB&NXcar*p<6ze00uzG)*jlsZ&FKs1 z%DQUP0p{eI<0IGEl&^m}sgs

ELnE?Qchod|OK^sO2CS$1jxHX6}CXOH1sJxYi@!noB92rIN#)f;glEF6+jMCELzf%wkroGCy>cxTsZ)>>aC3?T4WZ43KLMg00 zzse;gmu?^>C8b$jc93{XDQxu$NQ#Y~7v9X5Vd%z(C4;vMHC$ho1!zLDx-noR^6rq4 zkzY$uGA_jRhst5As$Qi6iTDuZ=eMIItg=>CBDJzOoF>x+CQxiM-26j|4OpAN)P>WL zbKs6d@8e%!7DG^8WXo`N(UW=^Xv8Z$-%M5rqQ(`eh_1oiG$z1Oict&GfZfW(V-dxJViKcP0#er!VN*GQ@IoRt3h&taEi==W%Gm6~i}dH?HF4qU&nt=e@J zo!I-JnXqgeywMVdSTx^nbio$W;A(hyY~@5a8C-D^Clk!?_E{0utuXy=yo|IzL^p=v zHzilEHR6r`)xlpr5L~1MB3S9go?cq{*q_%{ui%Vd#laa2#`LqeIQ&g+Jn%3Q<3z#4 z50^?r$^|;`Qnsb;at;wv$EH+8dPq6OjfYy#yT);TZfgzM;Q>oNo zYHe?J_k;p|!nd61P4V_<1%VJU)PMiOjp4$N`(%5Q3Eh%0H8*E@TW{{2Gl$9N^^7&0 z=L5}L$2h%B24rx`$of^7MD64y>fHx?W3e(=)V z(F>K*Qc}2j5Ukzt0@TZdujqp#XK=+TkKF8msM aVyF13&sk3w8VGgpfuFsti%k>KKlR_>u4haD delta 1720 zcmZ{ke>~H99LK3E*CU~Hm&!JAa;N-QCNpQU&D?gz@lY-*x{Xqp+je2bw@7r!nt9Zf zB2l}?Bjq9IG}<|oVI*9S)iGk+*{S)JHqCUO?^KT-mHqYleD-<0U!Nb(_qV~Jam^Wu z@#adZqp@(n*j5;Cd|249#95fJWaAzT(Zdakar5)_^u(aiek3db<4JHQVzHhWPa*;9 zZflbqpGc$ONKE=q@zDt!3d!3R%s4Y*8MxP8@?u`0dWq|s0ODecY;D+_kmwj3WAOme zVqRg!QUbIgw8hcLXxS|a$u~6l@27pVgrRSYP7E?yie#iA>qOT_O{;fUmxhUn>}6HU z(N{@_O1_AmR62$|?yNdk!l@|t$Ql#I>~lFMTbbJgA&prk;>4*`wLU)(`SZn?`p+={Rty6F}oR_?;IM2c%`O~v^ zVlPaj;4Y~(x(ShVh=aN|!_`0JTHxchZ|o$gn>bkO#=`cQphjJQw#30sV;t^$PSm67 zt#+S#AQb2x+->$RE$hqvXF#jHJ`pyEN~W?$M zsc3gn(sP4D)b1(sS$DzuLtjG*47E*Sw)gZ&U^=I+oJ1>XK4Aro!UA!WX)3ss62r?y zQz4vUR6O!~@J z$-%)(xBr~1?Dry%n+k&M4R(<#;AS>{!bDjSz@ED)fB{5(IcRf?mWi{~g%*3Kl5&bi#^Ho;1!rRfX z0jJo)mMtJmD}pw`6*hE6dVnXbAcoPe0MpgfI9`Cp=~$m77l>TaZxN^NuM3q&O#NWOQloeYj(Pl`pb?l zwEp<_E5OZEz=yQs?suiOrIF;mAipkH_UHh}Hxb1gQ_>{^1eQy9vV(IXuUwPYuW{z;ne=NV-Xg%J?6OHAAof diff --git a/client/public/stylesheets/layout.css b/client/public/stylesheets/layout.css index cd9d5b1e..63ccc67b 100644 --- a/client/public/stylesheets/layout.css +++ b/client/public/stylesheets/layout.css @@ -1,7 +1,7 @@ /* Page style */ body { - display: flex; + display: grid; margin: 0; padding: 0; } @@ -43,6 +43,33 @@ body { } +/**************************************/ + +.olympus-dialog { + align-self: center; + background:white; + border-radius: 10px; + display: flex; + flex-direction: column; + justify-self: center; + padding:10px; + position:absolute; + width:fit-content; + z-index: 9999; +} + +.olympus-dialog-close { + cursor:pointer; + position:absolute; + right:10px; + top:5px; +} + +.olympus-dialog-header { + font-weight:bold; +} + + /**************************************/ .control-panel { @@ -69,29 +96,49 @@ body { /***** AIC *****/ #aic-control-panel { - color:white; left: 550px; } -.aic-enabled #aic-control-panel .olympus-button { +#aic-control-panel .olympus-button { filter:invert(100%); } -#aic-formation-panel { +#aic-toolbox, #aic-callsign-panel { + align-items: flex-start; align-self: center; - background:#eaeaea; - border-bottom-right-radius: 10px; - border-top-right-radius: 10px; + flex-direction: column; + row-gap: 10px; display:none; - justify-self: left; - padding:10px; position:absolute; } -.aic-enabled #aic-formation-panel { +.aic-panel { + background:#eaeaea; + border-bottom-right-radius: 10px; + border-top-right-radius: 10px; + justify-self: left; + padding:5px 10px; +} + +.aic-enabled #aic-toolbox, .aic-enabled #aic-callsign-panel { display:flex; - flex-direction: column; +} + +.aic-enabled #aic-callsign-panel { + align-self: auto; + top: 100px; +} + +.aic-panel h2 { + font-size:90%; + margin:0; + padding:0; + text-align: center; +} + +#aic-callsign-display { + text-align: center; } #aic-formation-list { @@ -102,16 +149,95 @@ body { #aic-formation-list > div { align-items: center; + cursor: pointer; display:flex; flex-direction: column; justify-content: center; - margin-top:1em; + margin-top:10px; + position:relative; } #aic-formation-list .aic-formation-image img { border: 1px solid #ccc; border-radius: 10px; - max-width: 75px; + max-width: 50px; +} + +#aic-formation-list .aic-formation-name { + font-size:90%; +} + +#aic-formation-list .aic-formation-descriptor { + background:white; + border-radius: 10px; + left:100px; + padding:5px; + position:absolute; + width: max-content; +} + +#aic-teleprompt { + background-color: white; + border:2px solid black; + border-radius: 10px; + bottom: 50px; + color: black; + display: none; + justify-content: center; + justify-self: center; + padding: 10px; + position: absolute; + width: fit-content; + z-index: 1000; +} + +.aic-enabled #aic-teleprompt { + display:flex; +} + +#aic-descriptor { + display:flex; + flex-direction: row; +} + +#aic-descriptor .aic-descriptor-section { + display:flex; + flex-direction: column; + margin:0 10px; +} + +#aic-descriptor .aic-descriptor-section-label { + background-color:#eaeaea; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + padding:.25em; + text-align: center; +} + +#aic-descriptor .aic-descriptor-components { + display:flex; + flex-direction: row; +} + +#aic-descriptor .aic-descriptor-components .aic-descriptor-component { + margin:0 5px; + text-align: center; +} + +#aic-descriptor .aic-descriptor-component-label { + display:none; +} + +#aic-descriptor .aic-descriptor-component-value:after { + content:","; +} + +#aic-descriptor .aic-descriptor-component:last-of-type .aic-descriptor-component-value:after { + content:";"; +} + +#aic-descriptor .aic-descriptor-section:last-of-type .aic-descriptor-component:last-of-type .aic-descriptor-component-value:after { + content:"."; } @@ -162,4 +288,12 @@ body { #unit-control-panel { top: 50px; } +} + + + + + +.hide { + display:none !important; } \ No newline at end of file diff --git a/client/src/aic/aic.ts b/client/src/aic/aic.ts index 86a5e237..7fc70c64 100644 --- a/client/src/aic/aic.ts +++ b/client/src/aic/aic.ts @@ -1,37 +1,79 @@ -interface AICFormation { - "descriptor" : string, - "icon" : string, - "label" : string, - "name" : string -} +import { AICFormation } from "./AICFormation"; +import { AICFormation_Azimuth } from "./AICFormation/Azimuth"; +import { AICFormation_Range } from "./AICFormation/Range"; +import { AICFormation_Single } from "./AICFormation/Single"; +import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection"; +// import { AICFormationDescriptor } from "./aicformationdescriptor" export class AIC { #status:boolean = true; - #formations:AICFormation[] = [{ - "descriptor" : "group, single, Bullseye, , , , tracks , ", - "icon" : "single.png", - "label" : "Single", - "name" : "single" - }, { - "descriptor" : "", - "icon" : "azimuth.png", - "label" : "Azimuth", - "name" : "azimuth" - }, { - "descriptor" : "", - "icon" : "range.png", - "label" : "Range", - "name" : "range" - }]; + #formations = [ + + new AICFormation_Single(), + new AICFormation_Range(), + new AICFormation_Azimuth() + + ]; constructor() { this.#onStatusUpdate(); + // This feels kind of dirty + let $aicFormationList = document.getElementById( "aic-formation-list" ); + + if ( $aicFormationList ) { + + this.getFormations().forEach( formation => { + + // Image + let $imageDiv = document.createElement( "div" ); + $imageDiv.classList.add( "aic-formation-image" ); + + let $img = document.createElement( "img" ); + $img.src = "images/formations/" + formation.icon; + + $imageDiv.appendChild( $img ); + + // Name + let $nameDiv = document.createElement( "div" ); + $nameDiv.classList.add( "aic-formation-name" ); + $nameDiv.innerText = formation.label; + + // Wrapper + let $wrapperDiv = document.createElement( "div" ); + $wrapperDiv.dataset.formationName = formation.name; + $wrapperDiv.appendChild( $imageDiv ) + $wrapperDiv.appendChild( $nameDiv ); + $wrapperDiv.addEventListener( "click", ( ev ) => { + + const controlTypeInput = document.querySelector( "input[type='radio'][name='control-type']:checked" ); + + let controlTypeValue:any = ( controlTypeInput instanceof HTMLInputElement && [ "broadcast", "tactical" ].indexOf( controlTypeInput.value ) > -1 ) ? controlTypeInput.value : "broadcast"; + + // TODO: make this not an "any" + const output:any = formation.getDescriptor({ + "aicCallsign" : "Magic", + "bullseyeName" : "Bullseye", + "control" : controlTypeValue, + "numGroups" : formation.numGroups + }); + + this.updateTeleprompt( output ); + + }); + + // Add to DOM + $aicFormationList?.appendChild( $wrapperDiv ); + + }); + + } + } @@ -67,4 +109,80 @@ export class AIC { } + + toggleHelp() { + document.getElementById( "aic-help" )?.classList.toggle( "hide" ); + } + +//* + updateTeleprompt( descriptor:T[] ) { + + let $teleprompt = document.getElementById( "aic-teleprompt" ); + + if ( $teleprompt instanceof HTMLElement ) { + + // Clean slate + while ( $teleprompt.childNodes.length > 0 ) { + $teleprompt.childNodes[0].remove(); + } + + function newDiv() { + return document.createElement( "div" ); + } + + // Wrapper + let $descriptor = newDiv(); + $descriptor.id = "aic-descriptor"; + + for ( const section of descriptor ) { + + if ( section.omitSection ) { + continue; + } + + let $section = newDiv(); + $section.classList.add( "aic-descriptor-section" ); + + let $sectionLabel = newDiv(); + $sectionLabel.classList.add( "aic-descriptor-section-label" ); + $sectionLabel.innerText = section.label; + $section.appendChild( $sectionLabel ); + + + let $components = newDiv(); + $components.classList.add( "aic-descriptor-components" ); + + for ( const component of section.getComponents() ) { + + let $component = newDiv(); + $component.classList.add( "aic-descriptor-component" ); + + let $componentLabel = newDiv(); + $componentLabel.classList.add( "aic-descriptor-component-label" ); + $componentLabel.innerText = component.label; + + let $componentValue = newDiv(); + $componentValue.classList.add( "aic-descriptor-component-value" ); + $componentValue.innerText = component.value; + + $component.appendChild( $componentLabel ); + $component.appendChild( $componentValue ); + + $components.appendChild( $component ); + + } + + $section.appendChild( $components ); + $descriptor.appendChild( $section ); + + } + + $teleprompt.appendChild( $descriptor ); + + } + + + } +//*/ + } \ No newline at end of file diff --git a/client/src/index.ts b/client/src/index.ts index e1bc758a..2a826c75 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -11,8 +11,8 @@ import { MissionData } from "./missiondata/missiondata"; import { UnitControlPanel } from "./panels/unitcontrolpanel"; import { MouseInfoPanel } from "./panels/mouseInfoPanel"; import { Slider } from "./controls/slider"; +import { AIC } from "./aic/AIC"; -import { AIC } from "./aic/aic"; /* TODO: should this be a class? */ var map: Map; @@ -41,6 +41,7 @@ var deadVisibilityButton: Button; var aic: AIC; var aicToggleButton: Button; +var aicHelpButton: Button; var altitudeSlider: Slider; var airspeedSlider: Slider; @@ -84,11 +85,31 @@ function setup() { /* AIC */ aic = new AIC(); - - setupAICFormations( aic ); - aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/ai-full.svg"], () => { + aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/radar.svg"], () => { aic.toggleStatus(); + }); + + aicHelpButton = new Button( "aic-help-button", [ "images/buttons/question-mark.svg" ], () => { + aic.toggleHelp(); + }); + + + /* Generic clicks */ + + document.addEventListener( "click", ( ev ) => { + + if ( ev instanceof PointerEvent && ev.target instanceof HTMLElement ) { + + if ( ev.target.classList.contains( "olympus-dialog-close" ) ) { + ev.target.closest( "div.olympus-dialog" )?.classList.add( "hide" ); + } + + } + + + + }); /* Default values */ @@ -226,55 +247,4 @@ export function getUnitControlSliders() { } -function setupAICFormations( aic:AIC ) { - let $aicFormationList = document.getElementById( "aic-formation-list" ); - - if ( $aicFormationList ) { - - /* // Example display -

-
- -
-
Azimuth
-
(instructions)
-
- //*/ - - aic.getFormations().forEach( formation => { - - // Image - let imageDiv = document.createElement( "div" ); - imageDiv.classList.add( "aic-formation-image" ); - - let img = document.createElement( "img" ); - img.src = "images/formations/" + formation.icon; - - imageDiv.appendChild( img ); - - // Name - let nameDiv = document.createElement( "div" ); - nameDiv.classList.add( "aic-formation-name" ); - nameDiv.innerText = formation.label; - - // Descriptor - let descriptorDiv = document.createElement( "div" ); - descriptorDiv.classList.add( "aic-formation-descriptor" ); - descriptorDiv.innerText = formation.descriptor; - - // Wrapper - let wrapperDiv = document.createElement( "div" ); - wrapperDiv.dataset.formationName = formation.name; - wrapperDiv.appendChild( imageDiv ) - wrapperDiv.appendChild( nameDiv ); - wrapperDiv.appendChild( descriptorDiv ); - - // Add to DOM - $aicFormationList?.appendChild( wrapperDiv ); - - }); - - } -} - window.onload = setup; \ No newline at end of file diff --git a/client/src/other/utils.ts b/client/src/other/utils.ts index 4b169360..45ad1439 100644 --- a/client/src/other/utils.ts +++ b/client/src/other/utils.ts @@ -1,3 +1,37 @@ +export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) { + const φ1 = deg2rad(lat1); // φ, λ in radians + const φ2 = deg2rad(lat2); + const λ1 = deg2rad(lon1); // φ, λ in radians + const λ2 = deg2rad(lon2); + const y = Math.sin(λ2 - λ1) * Math.cos(φ2); + const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1); + const θ = Math.atan2(y, x); + const brng = (rad2deg(θ) + 360) % 360; // in degrees + + return brng; +} + + +export function ConvertDDToDMS(D: number, lng: boolean) { + var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N"; + var deg = 0 | (D < 0 ? (D = -D) : D); + var min = 0 | (((D += 1e-9) % 1) * 60); + var sec = (0 | (((D * 60) % 1) * 6000)) / 100; + var dec = Math.round((sec - Math.floor(sec)) * 100); + var sec = Math.floor(sec); + if (lng) + return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\""; + else + return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\""; +} + + +export function deg2rad(deg: number) { + var pi = Math.PI; + return deg * (pi / 180); +} + + export function distance(lat1: number, lon1: number, lat2: number, lon2: number) { const R = 6371e3; // metres const φ1 = deg2rad(lat1); // φ, λ in radians @@ -13,27 +47,24 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number) return d; } -export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) { - const φ1 = deg2rad(lat1); // φ, λ in radians - const φ2 = deg2rad(lat2); - const λ1 = deg2rad(lon1); // φ, λ in radians - const λ2 = deg2rad(lon2); - const y = Math.sin(λ2 - λ1) * Math.cos(φ2); - const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1); - const θ = Math.atan2(y, x); - const brng = (rad2deg(θ) + 360) % 360; // in degrees - return brng; +export function rad2deg(rad: number) { + var pi = Math.PI; + return rad / (pi / 180); } -export const zeroPad = function (num: number, places: number) { - var string = String(num); - while (string.length < places) { - string += "0"; + +export function reciprocalHeading( heading:number ): number { + + if ( heading > 180 ) { + return heading - 180; } - return string; + + return heading + 180; + } + export const zeroAppend = function (num: number, places: number) { var string = String(num); while (string.length < places) { @@ -42,25 +73,11 @@ export const zeroAppend = function (num: number, places: number) { return string; } -export function ConvertDDToDMS(D: number, lng: boolean) { - var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N"; - var deg = 0 | (D < 0 ? (D = -D) : D); - var min = 0 | (((D += 1e-9) % 1) * 60); - var sec = (0 | (((D * 60) % 1) * 6000)) / 100; - var dec = Math.round((sec - Math.floor(sec)) * 100); - var sec = Math.floor(sec); - if (lng) - return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\""; - else - return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\""; -} -export function deg2rad(deg: number) { - var pi = Math.PI; - return deg * (pi / 180); -} - -export function rad2deg(rad: number) { - var pi = Math.PI; - return rad / (pi / 180); +export const zeroPad = function (num: number, places: number) { + var string = String(num); + while (string.length < places) { + string += "0"; + } + return string; } \ No newline at end of file diff --git a/client/views/aiccontrolpanel.ejs b/client/views/aiccontrolpanel.ejs index 1a3282cd..e4f11833 100644 --- a/client/views/aiccontrolpanel.ejs +++ b/client/views/aiccontrolpanel.ejs @@ -1,3 +1,17 @@
-
\ No newline at end of file +
+ + +
+
×
+
AIC Help
+
+

How to be a good AIC and get people to do stuff good, too.

+
+
[DCS with Volvo video]
+
+
+
+ +
\ No newline at end of file diff --git a/client/views/aicformationpanel.ejs b/client/views/aicformationpanel.ejs index 3dae4b29..5d6f2d5b 100644 --- a/client/views/aicformationpanel.ejs +++ b/client/views/aicformationpanel.ejs @@ -1,7 +1,33 @@ -
+
+ +
+

My callsign

+
Magic
+
+ +
+ + +
-
Formations
+
+

Control

+
+ + +
+
+ + +
+
+ +
+ +

Formations

+ +
+ +
-
- -
\ No newline at end of file +