 (* calculate arctan(y/x)  *)
open TypeBase
open TypeTracks

  node myarctan(y, x : float) returns (atan : float)
  var l6 : float; l4 : bool; l1 : float;
  let
    atan =
      if l4
      then if x <. 0.0 then CstPhysics.pi +. l1 else l1
      else CstPhysics.pi /. 2.0 *. Math.sign(y);
  (*  l6 = (activate div every l4 initial default 0.0)(y, x);  *)
    l6 = if l4 then y /. x else 0.0 -> pre l6;
    l4 = Math.abs(x) >. 0.1;
    l1 = Mathext.atanr(l6);
  tel

(* compute if a given track is equal to one of the mission tracks
   belonging to the mission track array at the previous tick *)
fun missiontrackequalsprevious(previousone, actualone : TypeTracks.tmissiontrack)
    returns (equal : bool)
let
    equal =
      0 <> previousone.m_id & previousone.m_id = actualone.m_id or
      Math.abs(previousone.m_pos.x -. actualone.m_pos.x) <. 100.0 &
      Math.abs(previousone.m_pos.y -. actualone.m_pos.y) <. 100.0 &
      not (Math.abs(previousone.m_pos.x) <. 0.1 &
       Math.abs(previousone.m_pos.y) <. 0.1 &
       Math.abs(actualone.m_pos.x) <. 0.1 &
       Math.abs(actualone.m_pos.y) <. 0.1 )
tel

  (* compute track visibility (appearance on radar screen)
     according to track position and speed  *)
fun calctrackvisible1(position : TypeBase.tposition;
                             speed : TypeBase.tspeed)
    returns (trackvisible : bool)
let
  trackvisible =
      not (Math.abs(position.x) <. 0.001 & Math.abs(position.y) <. 0.001 &
       Math.abs(speed.sx) <. 0.001 &
       Math.abs(speed.sy) <. 0.001);
tel

fun missiontrackexist1(acc_tracknumber : int;
                              missiontrack,
                              previousmissiontrack : TypeTracks.tmissiontrack)
  returns (tracknumbertoset : int)
let
    tracknumbertoset =
      if missiontrackequalsprevious(missiontrack, previousmissiontrack) &
      0 <> previousmissiontrack.m_tracknumber
      then previousmissiontrack.m_tracknumber
      else acc_tracknumber;
tel

(* compute if a given track is equal to one of the mission tracks
   belonging to the mission track array at the previous tick *)
fun missiontrackequalsprevious_orig(previousone, actualone : TypeTracks.tmissiontrack)
    returns (equal : bool)
var l43 : bool;
let
    l43 = previousone.m_tracknumber <> 0;
    equal =
      l43 &
      (l43 & 0 <> previousone.m_id & previousone.m_id = actualone.m_id or
       Math.abs(previousone.m_pos.x -. actualone.m_pos.x) <. 100.0 &
       Math.abs(previousone.m_pos.y -. actualone.m_pos.y) <. 100.0 &
       not (Math.abs(previousone.m_pos.x) <. 0.1 &
        Math.abs(previousone.m_pos.y) <. 0.1 &
        Math.abs(actualone.m_pos.x) <. 0.1 &
        Math.abs(actualone.m_pos.y) <. 0.1));
tel

fun util_radtodeg(input1 : float) returns (output1 : float)
let
  output1 = input1 /. (2.0 *. CstPhysics.pi) *. 360.0;
tel

fun util_degtorad(input1 : float) returns (output1 : float)
let
  output1 = 2.0 *. CstPhysics.pi *. input1 /. 360.0;
tel

(* if speedabs is small (speed.x and speed.y are also small), trackangle is set to 0.
   otherwise, trackangle is computed to be in the range [-180, 180]
    degrees thanks to the acosr; sign is given, from the asinr. *)
fun calctrackangle(speed : TypeBase.tspeed; speedabs : TypeBase.tmetresseconde)
    returns (trackangle : float)
var l51 : bool; l48, l47 : float;
let
    trackangle =
      util_radtodeg(if l51 then 0.0 else Mathext.acosr(l47) *. l48) *.
      (l48 *.
       Math.sign(Mathext.asinr(speed.sy /. (if l51 then 1.0 else speedabs))));
    l51 = speedabs <. 0.01;
    l48 = Math.sign(l47);
    l47 = speed.sx /. (if l51 then 1.0 else speedabs);
tel

(* compute track visibility (appearance on radar screen)
   according to track position *)
fun calctrackvisible(position : TypeBase.tposition)
    returns (trackvisible : bool)
let
 trackvisible =
      not (Math.abs(position.x) <. 0.001 & Math.abs(position.y) <. 0.001);
tel

fun missiontrackexist( missiontrack,
                       previousmissiontrack : TypeTracks.tmissiontrack;
                       acc_tracknumber : int)
    returns (tracknumbertoset : int)
let
    tracknumbertoset =
      if missiontrackequalsprevious(missiontrack, previousmissiontrack)
      then previousmissiontrack.m_tracknumber
      else acc_tracknumber;
tel

(* calculate: result = rate of closing / distance *)
node calculatevrdivd(vr, d : float) returns (result : float)
var l13 : float; l11 : bool;
let
  result = if l11 then l13 else 0.0;
(*    l13 = (activate div every l11 initial default 0.0)(vr, d);  *)
  l13 = if l11 then vr /. d else 0.0 -> pre l13;
  l11 = d >. 0.1;
tel

(* sort two mission tracks according to:
  1) their (rate of closing / distance) ratio
  2) target type
  3) detection or not by the radar *)
node trackalowerprioritythanb(a, b : TypeTracks.tmissiontrack)
  returns (prioritary : bool)
let
  prioritary =
      a.m_targettype = TypeBase.Ttargettype_friend or not a.m_detectedbyradar or
      a.m_detectedbyradar &
      calculatevrdivd(a.m_sr, a.m_d) <. calculatevrdivd(b.m_sr, b.m_d) &
      b.m_detectedbyradar;
tel

(* compute if two tracks speeds are equal *)
fun comparespeeds(speed1, speed2 : TypeBase.tspeed)
    returns (equal : bool)
let
  equal =
      Math.abs(speed1.sx -. speed2.sx) <. 1.0 &
      Math.abs(speed1.sy -. speed2.sy) <. 1.0;
tel

(* compute a "prioritized" track number according to its
   priority and target type *)
fun calculateprioritizedtracknb(missiontrack : TypeTracks.tmissiontrack)
    returns (prioritizedtracknb : int)
let
  prioritizedtracknb =
      if missiontrack.m_targettype <> TypeBase.Ttargettype_friend &
      missiontrack.m_priority <> 0
      then missiontrack.m_tracknumber
      else 0;
tel

(* sort two real inputs *)
fun sortreals(a, b : float) returns (newa, newb : float)
var l2 : bool;
let
  l2 = a <. b;
  newb = if l2 then a else b;
  newa = if l2 then b else a;
tel

(* compute if two tracks positions are equal *)
fun comparepositions(pos1, pos2 : TypeBase.tposition)
    returns (equal : bool)
let
    equal =
      Math.abs(pos1.x -. pos2.x) <. 0.1 & Math.abs(pos1.y -. pos2.y) <. 0.1;
tel

(* compute if two tracks are equal (according to their position
   and speed)  *)
fun comparetracks(pos1, pos2 : TypeBase.tposition;
                         v1, v2 : TypeBase.tspeed)
  returns (equal : bool)
let
    equal = comparepositions(pos1, pos2) & comparespeeds(v1, v2);
tel


(* set the track number of a mission track *)
fun setmissiontracknumber(missiontrack : TypeTracks.tmissiontrack at r; number : int)
    returns (newmissiontrack : TypeTracks.tmissiontrack at r)
let
    newmissiontrack = { missiontrack with .m_tracknumber = number };
tel

(* compute if a mission track is null (or empty) according to
   its position and speed *)
fun missiontrackisnull(missiontrack : TypeTracks.tmissiontrack)
    returns (isnull : bool)
let
    isnull =
      comparetracks(missiontrack.m_pos, CstBaseInit.kInitPosition,
        missiontrack.m_speed, CstBaseInit.kInitSpeed);
tel

(* calculate the new track number for a mission track, according to:
  1) the mission track data
  2) the previous mission tracks array
  3) the current (highest) track number *)
fun calculatemissiontracknumber(
               previousmissiontracks : TypeArray.tmissiontracksarray;
               missiontrack : TypeTracks.tmissiontrack at r;
               currenttracknumber : int)
    returns (newmissiontrack : TypeTracks.tmissiontrack at r;
             newtracknumber : int)
var setnewtracknumber : bool; previoustracknumber : int;
let
    setnewtracknumber =
      previoustracknumber = 0 & not missiontrackisnull(missiontrack);
    newtracknumber =
      if setnewtracknumber then currenttracknumber + 1 else currenttracknumber;
    previoustracknumber =
      fold <<TypeArray.ksizemissiontracksarray>> missiontrackexist
      <(missiontrack)>
      (previousmissiontracks, 0);
    newmissiontrack =
      setmissiontracknumber(missiontrack, if setnewtracknumber
        then newtracknumber
        else previoustracknumber);
tel

(* compute a mission track target type according to its identifier *)
fun calculatetracktargettypefromid(id : int)
    returns (targettype : TypeBase.ttargettype)
let
  targettype =
      if 0 = id
      then TypeBase.Ttargettype_unknown
      else if id <= 500
      then TypeBase.Ttargettype_friend
      else TypeBase.Ttargettype_foe;
tel

(* calculate the derivative of a value x(n) according to its
   ante-previous value x(n-2) *)
node myderivative(inv, period : float) returns (o : float)
var l2 : float;
let
 (* l2 = fby (inv; 2; 0.0);  *)
  l2 = 0.0 fby (0.0 fby inv);
  o =
      if Math.abs(l2) <. 0.1 or Math.abs(inv) <. 0.1
      then 0.0
      else 0.0 -> (inv -. l2) /. (2.0 *. period);
  tel

(* calculate a track speed vector according to the position vector *)
node calculatetrackspeedfrompos(position : TypeBase.tposition)
    returns (speed : TypeBase.tspeed)
let
  speed =
      { sx = myderivative(position.x, CstPhysics.t);
        sy = myderivative(position.y, CstPhysics.t) };
tel

(* generate the (up to 2) tracks detected by a sensor (radar
   or iff) from the environment (made of 4 tracks)  *)
fun selectdetectedtrack(index : int;
                        tracks : TypeArray.ttracksarray;
                        defaulttrack : TypeTracks.ttrack)
    returns (trackselected : TypeTracks.ttrack)
let
  trackselected = tracks.[index] default defaulttrack;
tel

(* set the priority of a mission track *)
fun setmissiontrackpriority(missiontrack : TypeTracks.tmissiontrack at r;
                                   priority : int)
    returns (newmissiontrack : TypeTracks.tmissiontrack at r)
let
  newmissiontrack =
   { missiontrack with .m_priority =
               if missiontrack.m_detectedbyradar then priority else 0 }
tel

(* invert two mission tracks if the first one is null (or empty)  *)
fun sortblockmissiontrack(a, b : TypeTracks.tmissiontrack)
    returns (newa, newb : TypeTracks.tmissiontrack)
var l7 : bool;
let
  l7 = missiontrackisnull(a);
  newb = if l7 then a else b;
  newa = if l7 then b else a;
tel

(* sort two mission tracks according to:
   1) their (rate of closing / distance) ratio
   2) target type
   3) detection or not by the radar *)
node sortblockpriorities(a, b : TypeTracks.tmissiontrack)
  returns (newa, newb : TypeTracks.tmissiontrack)
var l25 : bool;
let
    l25 = trackalowerprioritythanb(a, b);
    newb = if l25 then a else b;
    newa = if l25 then b else a;
tel

fun position_equal(p1, p2 : TypeBase.tposition) returns (res:bool)
let
  res = (p1.x = p2.x) & (p1.y = p2.y)
tel

fun speed_equal(s1, s2 : TypeBase.tspeed) returns (res:bool)
let
  res = (s1.sx = s2.sx) & (s1.sy = s2.sy)
tel

(* convert an iff track (position + identifier) into a mission
   track (position + speed + distance + rate of closing +
   detected by radar/iff + tracknumber + target type) *)
node convertifftracktomissiontrack(ifftrack : TypeTracks.tifftrack)
  returns (missiontrack : TypeTracks.tmissiontrack)
let
  missiontrack =
      { m_pos             = ifftrack.i_pos;
        m_speed           = if position_equal(CstBaseInit.kInitPosition, ifftrack.i_pos)
        then CstBaseInit.kInitSpeed
        else calculatetrackspeedfrompos(ifftrack.i_pos);
        m_id              = ifftrack.i_id;
        m_priority        = 0;
        m_d               = 0.0;
        m_sabs            = 0.0;
        m_sr              = 0.0;
        m_detectedbyradar = false;
        m_detectedbyiff   = not (position_equal(ifftrack.i_pos, CstBaseInit.kInitPosition) &
         ifftrack.i_id = 0);
        m_tracknumber     = 0;
        m_targettype      = calculatetracktargettypefromid(ifftrack.i_id);
        m_isvisible       = calctrackvisible(ifftrack.i_pos);
        m_angle           = 0.0 };
tel

(* convert an radar track (position + speed + distance +
   rate of closing) into a mission track (position + speed +
   distance + rate of closing + detected by radar/iff +
   tracknumber + target type)  *)
fun convertrdrtracktomissiontrack(rdrtrack : TypeTracks.trdrtrack)
    returns (missiontrack : TypeTracks.tmissiontrack)
let
    missiontrack =
      { m_pos             = rdrtrack.r_pos;
        m_speed           = rdrtrack.r_s;
        m_id              = 0;
        m_priority        = 0;
        m_d               = rdrtrack.r_d;
        m_sabs            = rdrtrack.r_sabs;
        m_sr              = rdrtrack.r_sr;
        m_detectedbyradar = not (position_equal(rdrtrack.r_pos, CstBaseInit.kInitPosition) &
         speed_equal(rdrtrack.r_s, CstBaseInit.kInitSpeed) &
         rdrtrack.r_d = 0.0 &
         rdrtrack.r_sabs = 0.0 &
         rdrtrack.r_sr = 0.0);
        m_detectedbyiff   = false;
        m_tracknumber     = 0;
        m_targettype      = TypeBase.Ttargettype_unknown;
        m_isvisible       = calctrackvisible(rdrtrack.r_pos);
        m_angle           = calctrackangle(rdrtrack.r_s, rdrtrack.r_sabs) };
tel

(* calculate the magnitude of a vector (2d)  *)
fun vectnorme(a, b : float) returns (c : float)
let
  c = Mathext.sqrtr(a *. a +. b *. b);
tel

(* extract the x and y (position) values from a track (ttrack type) *)
fun extracttrackposxy(track : TypeTracks.ttrack)
    returns (x, y : TypeBase.tmetres)
let
  y = track.t_pos.y;
  x = track.t_pos.x;
tel

(* elaborate radar track data (position, speed, distance, rate of closing)
  according to an environment track (position only)  *)
node elaboraterdrtrack(track : TypeTracks.ttrack)
    returns (rdrtrack : TypeTracks.trdrtrack)
var d, v, vr, vx, vy, x, y : float; l142 : TypeBase.tspeed;
let
    (*activate ifblock1 if d = 0.0
      then vr = 0.0;
      else var xnorm, ynorm : real;
      let
        ynorm = y / d;
        xnorm = x / d;
        vr = - (vx * xnorm + vy * ynorm);
      tel
    returns vr;*)
    switch d = 0.0
      | true do  vr = 0.0
      | false
        var xnorm, ynorm : float;
        do
          ynorm = y /. d;
          xnorm = x /. d;
          vr = -. (vx *. xnorm +. vy *. ynorm);
    end;

    (x, y) = extracttrackposxy(track);
    rdrtrack =
      { r_pos  = { x = x;
                 y = y };
        r_s    = { sx = vx;
                 sy = vy };
        r_d    = d;
        r_sabs = v;
        r_sr   = vr };
    v = vectnorme(vx, vy);
    d = vectnorme(x, y);
    vy = l142.sy;
    vx = l142.sx;
    l142 = calculatetrackspeedfrompos({ x = x; y = y });
tel

