// incline3.c
// incline for logarithmic altitude launch loop track
// with ramp and new track
// also reverse track

#define CL  80000.0    // cable material support length
#define C0  20000.0    // z0 for cable 
#define CS  0.7        // Sideways fraction for cable

#define OX  -156323.926 // x data offset in meters

#define X0  -20000.0   // Before ramps
#define X1  200000.0   // End of track
#define WZ  50550.0    // West station east altitude
#define WA  5.48       // West station angle degrees
#define WR  14000.0    // West station curvature radius
#define TC  3.2E-7     // track curvature at west station

#define VR  14000.0    // rotor speed at top of loop
#define RE  6378000.0  // Earth Radius
#define AG  9.81       // ag0
#define A0  20.0       // incline start angle degrees
#define MF  3.000      // ms/mr
#define MR  3.000      // rotor mass per meter
#define DX  1          // computation delta x in meters
#define NP  1000       // number of computation points per print
#define HT  80000.0    // top of loop, meters
#define LL  2000000.0  // launch loop length
#define K   1000.0     // kilo
#define EPS 1E-4       // comparison error

#include <stdio.h>
#include <math.h>

int       p   ;   // print counter
double    ra  ;   // degrees to radians
double    x   ;   // horizontal distance in meters
double    z   ;   // height in meters
double    zp  ;   // slope
double    zpp ;   // curvature in inverse meters
double    vr  ;   // rotor speed
double    vr2 ;   // rotor speed squared
double    vr0 ;   // surface rotor speed
double    l   ;   // length of incline
double    dl2 ;   // delta length squared
double    g   ;   // cable angle ratio
double    wz  ;   // west station magnet radius center z 
double    wx  ;   // west station magnet radius center x
double    ag  ;   // gravity at altitude
double    zw  ;   // west station west end altitude
double    dx  ;   // increment for drawing west station
double    xw  ;   // west station x length
double    rx  ;   // ramp center horizontal
double    rz  ;   // ramp center vertical
double    a0  ;   // ramp angle in radians
double    a1  ;   // ramp feed part angle in radians
double    an  ;   // ramp angle loop index
double    da  ;   // ramp angle loop increment
double    z1  ;   // height of reverse track
double    zp1 ;   // slope of reverse track

// -----------------------------------------

int  prxz() {
   double sprt = MR * ((vr*vr*(zpp+1.0/RE)/ag) - 1.0 ) ;
   double xo   = x + OX ;
   printf( "%11.6f%11.6f%12.6f%10.6f%10.3f%11.3f%9.5f%11.6f\n",
             xo/K,  z/K,  l/K,   zp, sprt,   vr,   ag, z1/K );
   return 0 ;
}

// -----------------------------------------
int main() {

   // initialization -------------------------------------------------------

   ra    = atan(1.0)/45.0 ;      // degrees to radians conversion constant
   vr0   = sqrt( VR*VR+2.0*AG*HT/( 1.0 + HT/RE ) ) ; // rotor ground speed
   ag    = AG             ;      // gravity at ground

   // -----------------------------------------------------------------------
   // ramp

   dx = 0.2*rx ;

   a0   = ra*A0                   ;  // radians, second upturn and start of ramp
   a1   = acos(0.5*(1.0+cos(a0))) ;  // radians, downturn and first upturn

   x    = X0       ;
   z    = 0.0      ;
   l    = x - WR * ( (a0-sin(a0)) + 2.0*(a1-sin(a1)) ) ;
   zp   = 0.0      ;
   zpp  = 1.0/RE   ;
   vr   = vr0      ;

   z1 = z ;
   prxz();

   // ramp downturn

   rx = -WR*(sin(a0)+2*sin(a1));
   rz = -WR ;

   da   = 0.2*a1   ;

   for( an=0.0 ; an < a1-EPS ; an += da ) {
      x   = rx+WR*sin(an);
      z   = rz+WR*cos(an);
      l   = WR*(a0+2.0*a1-an);
      zp  = -tan( an );
      zpp = 1.0/(WR*cos(an)*cos(an))  ;
      vr2 = vr0*vr0-2.0*AG*z/(1.0 + z/RE ) ;
      vr  = sqrt( vr2 );
      ag  = 1.0/(1.0+(z/RE)) ;
      ag *= AG*ag ;
   
      z1 = z ;
      prxz();
   }

   // ramp upturn

   rx = -WR*sin(a0) ;
   rz =  WR*cos(a0) ;

   da   = 0.1*(a0+a1)   ;
   for( an= -a1 ; an < a0-EPS ; an += da ) {
      x   = rx+WR*sin(an);
      z   = rz-WR*cos(an);
      l   = WR*(a0-an);
      zp  = tan( an );
      zpp = -1.0/(WR*cos(an)*cos(an))  ;
      vr2 = vr0*vr0-2.0*AG*z/(1.0 + z/RE ) ;
      vr  = sqrt( vr2 );
      ag  = 1.0/(1.0+(z/RE)) ;
      ag *= AG*ag ;

      z1 = z ;
      prxz();
   }

   // -----------------------------------------------------------------------
   // incline

   // initialize

   x     = 0.0            ;
   p     = NP             ;
   z     = 0.0            ;      // 
   zp    = tan( a0 )      ;      // first spatial derivative
   l     = 0.0            ;
   wz    = WZ - WR * cos( ra*WA )   ;

   //  main loop
   while( p >= 0 ) {
      ag  = 1.0/(1.0+(z/RE)) ;
      ag *= AG*ag ;
      vr2 =  vr0*vr0-2.0*AG*z/(1.0 + z/RE ) ;
      vr  = sqrt( vr2 );
      g   = sqrt( exp( 2.0*( z+C0 ) / CL ) - 1.0 ) ;
      dl2 = 1.0+zp*zp ;
      zpp = dl2 * ( (1.0/(RE+z)) + dl2*ag*MF/(vr2*(1.0-g*zp )) ) ;

      if( p++ >= NP ) {
         z1  = z ;
         prxz() ; // print every 1000 meters
         p = 1 ;
      }
      
      // increment values
      x  += DX       ;
      zp -= zpp * DX ;
      z  += zp  * DX ;
      l  += DX*sqrt(dl2);

      // compute west station west end height  WZ

      zw  =  wz + WR / sqrt( 1.0 + zp*zp ) ;
 
      // test for completion

      if ( z > zw ) { p = -NP ; }
   }
   z1  = z ;
   prxz();

   // --------------------------------------------------------------------
   // now, compute points for west station 

   wx = x + WR*zp/sqrt( 1.0+zp*zp)  ;  // west station radius x center
   xw = wx - WR*sin( ra * WA )      ;  // west station east end x location

   // find angles

   a0 = -acos( ( z-wz)/WR ) ;
   a1 = -acos( (WZ-wz)/WR ) ;
   da = 0.2*(a1-a0) ;

   for( an = a0+da ; an < a1+EPS ; an += da ) {
      x   = wx + WR*sin( an );
      z   = wz + WR*cos( an );
      zp  = -tan( an );
      zpp = 1.0/(WR*cos(a0)*cos(a0)) ;   
      ag  = 1.0/(1.0+(z/RE)) ;
      ag *= AG*ag ;
      vr2 =  vr0*vr0-2.0*AG*z/(1.0 + z/RE ) ;
      vr  = sqrt( vr2 );
      l  += da*WR ;

      // reverse track
      z1  = z ;
      prxz();
   }

   // --------------------------------------------------------------------
   //  compute points for first part of track, constant curvature
   //  also reverse track

   p   = 1  ;
   zpp = TC ;
   zp  = tan( ra * WA );
   zp1 = (HT-WZ)/LL ;

   while ( x <= X1 ) {
      x  += DX     ;
      z  += zp*DX  ;
      zp -= zpp*DX ;
      l  += DX*sqrt(1.0+zp*zp);
      ag  = 1.0/(1.0+(z/RE)) ;
      ag *= AG*ag ;
      vr2 =  vr0*vr0-2.0*AG*z/(1.0 + z/RE ) ;
      vr  = sqrt( vr2 );

      if( p++ >= NP ) {

         // reverse track, more station then flat

         dx = x - wx ;

         if( dx <  0 ) {
            z1 = wz + sqrt( WR*WR-dx*dx );
         } else {
            z1 = dx*zp1+wz+WR ;
         }

         prxz() ; // print every 1000 meters
         p = 1 ;
      }
   }

   // --------------------------------------------------------------------
   return 0 ;
}
