// uniformly illuminated parabolic dish, beam
//
// compile with:       cc -o adish03 adish03.c -lgd -lpng -lm
#  define NAME      "adish03"
//
// Uses the libgd library.  For documentation see the file:
//      /usr/share/doc/gd-*/index.html  
//   or the website:  http://www.libgd.org/Reference
//  
// You will need truetype fonts, "apt search dejavu" returns
// fonts-dejavu-core/focal,focal,now 2.37-1 all [installed,automatic]
//
// Uses /usr/local/bin/apngasm to make APNG animation from frames
// /home/keithl/src/apngasm/apngasm-2.91-src.zip
//
// now uses j1 function and math.h
//
// This constructs 30 images then dups them forward and reverse.

#include "gd.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define  RMMKDIR     "rm -rf adish03dir ; mkdir adish03dir"
#define  PNG2APNG    "/usr/local/bin/apngasm adish03.png adish03dir/* 1 10"
#define  PNGFMT      "adish03dir/a%04d.png"

#define  YCENT       130
#define  INTPTS      100          // integration points 
#define  WAVELENGTH  86.0         // radio wavelength in pixel units
#define  SCALE       200.0        // disk scaling in pixel units
#define  NPICS       40           // number of frames

#define  XSIZE       1000         // display window in pixels
#define  YSIZE       750          // display window in pixels
#define  FNT         "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"
#define  FSZ         10

double   amult[XSIZE][YSIZE]     ; //
double   aphase[XSIZE][YSIZE]    ; //
double   behind[XSIZE][YSIZE]    ; //

// ==========================================================================

int main() {

   gdImagePtr im                    ; // pixel image map used by gd
   gdPoint  beam[4]                 ; // trapezoidal output beam
   double   lambda =     WAVELENGTH ; //
   double   scale  = (double) SCALE ; // dish scale
   double   yacent = (double) YCENT ; // center of upper drawing
   double   xsize  = (double) XSIZE ; // width of pixels
   double   ysize  = (double) YSIZE ; // height of pixels
   int      ybot   = 2*YCENT        ; // top of output pixel array
   double   dybot  = (double) ybot  ; // real ""
   double   pi2    = 8.0*atan(1.0)  ; // two times PI
   double   d2r    = pi2/360.0      ; // degrees to radians conversion factor
   int      oxc    = XSIZE/2        ; // center of output pixel array
   int      oyc    = YSIZE/2        ; // center of output pixel array
   double   xacent = (double) oxc   ; // real ""
   int      brect[8]                ; // this returns an (ignored) bounding box
   FILE     *pngout                 ; // file handle for PNG output frame
   char     dirname[200]            ; // frame output directory
   char     framename[200]          ; // directory/name of frame
   char     labstring[200]          ; // used for labellin
   char     rmmkdir[200]            ; // remove and make frame directory
   char     link0[200]              ; // directory/name of source 
   char     link1[200]              ; // directory/name of target hardlink
   int      black, sun1, white, red ; // color map numbers
   int      green, blue, gray       ; // color map numbers
   int      dgray, trans            ; // color map numbers
   int      bcolor[256]             ; // color map numbers
   int      gcolor[256]             ; // color map numbers
   int      ox, oy                  ; // output pixel position
   int      oxm                     ; //
   int      i                       ; // general counter
   int      fs                      ; // big label font size
   int      cir                     ; //
   double   dcir                    ; //
   int      icolor                  ; //
   int      jcolor                  ; //
   int      mag                     ; // pixel magnitude, 0-255
   int      frame                   ; // animation frame count
   int      pct=0                   ; // percentage of complete frame
   int      pct0=0                  ; // previous percentage
   int      ya= YCENT               ; // antenna height
   double   bx                      ; // bessel argument
   double   j                       ; // 
   double   j0                      ; // 
   double   ffrac                   ; // frame scaling of variable, 0 to 1
   double   phase                   ; // phase
   double   k=pi2/lambda            ; // wavenumber
   double   oxd                     ; // 
   double   oxd2                    ; // 
   double   oyd                     ; //
   double   oyd2                    ; //
   double   oym                     ; //
   double   dis                     ; // distance from focus spot
   double   dis2                    ; // 
   int      rate = 20               ; // swf rate
   double   xm                      ; //
   double   max                     ; // normalize beam amplitude
   double   norm                    ; // normalize beam amplitude
   double   delta                   ; //
   double   sumsin                  ; //
   double   sumcos                  ; //
   double   sum                     ; //
   double   adis                    ; //
   double   amp[INTPTS]             ; //
   double   dn, da, di              ; //

//  set up target directory

   system( RMMKDIR );

//  make array amplitude values ------------------------------------------
   
   for( i=0 ; i<INTPTS ; i++ ) {
      dn = ( (double)INTPTS ) ;
      di = (double) i      ;
      da = (2.0*di+1.0-dn)/dn;
      amp[i]=sqrt(1.0-da*da );
      // DEBUG printf( "%3d%12.6f\n", i, amp[i] );
   }

//  make phase and magnitude array ---------------------------------------

   max   = 0.0 ;
   cir   = (int) (0.39*scale)      ;
   dcir  = (double) cir            ;
   xm    = 2.0*dcir                ;
   delta = 2.0*xm/((double)INTPTS) ;
   xm   -= 0.5*delta-xacent        ;
   dcir *= 0.99*dcir               ;

   for( oy=0 ; oy<YSIZE ; oy++ ) {
      oyd   = (double)(oy-ya) ;
      oyd2  = oyd*oyd ;
      oym   = 0.5/(0.5+exp(-0.1*oyd ) ) ; // kludge!!

      printf( "setup %04d/%04d\r", oy, YSIZE ) ;
      fflush(stdout);

      // do half the array, then mirror
      for( ox=0 ; ox < oxc ; ox++ ) {
         oxd = xm - (double)ox ;
         sumsin = 0.0 ;
         sumcos = 0.0 ;
         for( i=0 ; i<INTPTS ; i++ ) {
            oxd2    = oxd*oxd ;
            dis2    = oxd2 + oyd2 ;
            dis     = sqrt( dis2 );
            sumsin += amp[i]*sin( k*dis ) / dis;
            sumcos += amp[i]*cos( k*dis ) / dis;
            oxd    -= delta ;
         }

         // is it behind the antenna?
         oxd  = (double) ( ox-oxc );
         oyd  = (double) ( oy-ya  );
         adis = 0.25*oxd*oxd + 4.0*oyd*oyd ;
         if( adis > dcir ) {
            sum            = sqrt(  sumsin*sumsin + sumcos*sumcos ) ;
// normalization kludge !!!
            sum           *= oym*sqrt(oxd*oxd + oyd*oyd);

            amult[ox][oy]  = sum ;
            aphase[ox][oy] = atan2( sumsin, sumcos );
            if( max < sum ) { max = sum ; }
          }
          else {
             amult[ox][oy]  = 0.0 ;
             aphase[ox][oy] = 0.0 ;
          }
   }  }

   // normalize and mirror

   norm = 1.0 / max ;

   for( oy=0 ; oy<YSIZE ; oy++ ) {
      for( ox=0 ; ox<oxc ; ox++ ) {
         amult[ox][oy] *= norm ;
         oxm = XSIZE-(ox+1);
         amult[ oxm][oy] = amult[ ox][oy] ;
         aphase[oxm][oy] = aphase[ox][oy] ;
   }  }
         
   printf("                  \r");

//  outer loop, sinusodial random factor change --------------------------
//  from 0 to 1 to 0
  
   for( frame=0 ; frame<NPICS ; frame++ ) {
      phase = pi2*((double)frame)/((double)(NPICS-1));

// set up array and define colors -----------------------------------------

      im = gdImageCreateTrueColor(XSIZE, YSIZE );
   
      // Allocate standard colors
      black = gdImageColorAllocate(im,   0,   0,   0);
      white = gdImageColorAllocate(im, 255, 255, 255);
      sun1  = gdImageColorAllocate(im,  51,  51, 102);
      red   = gdImageColorAllocate(im, 255,   0,   0);
      green = gdImageColorAllocate(im,   0, 255,   0);
      blue  = gdImageColorAllocate(im,   0,   0, 255);
      gray  = gdImageColorAllocate(im, 160, 160, 160);
      dgray = gdImageColorAllocate(im,  48,  48,  48);
      trans = gdImageColorAllocate(im, 1, 1, 1);
   
      // allocate gray scale array 
      for( icolor=0 ; icolor<256 ; icolor++ ) {
        gcolor[icolor] = gdImageColorAllocate(im, icolor,   icolor,   icolor);
        bcolor[icolor] = gdImageColorAllocate(im, icolor/3, icolor, icolor/3);
      }

      printf( "%04d/%04d\r", frame, NPICS ) ;
      fflush(stdout);

// compute pixels ---------------------------------------------------------
   
      for( ox=0 ; ox<XSIZE ; ox++ ) {
         for( oy=0 ; oy<YSIZE ; oy++ ) {
            j  = amult[ox][oy]*sin( phase-aphase[ox][oy] ) ;
            if( j >  1.0 ) { j= 1.0; }
            if( j < -1.0 ) { j=-1.0; }
            mag = (int) ( 127.5*(1.0 + j ));
            gdImageSetPixel( im, ox,             oy, gcolor[mag] ) ;
      }  } 
  
 // labels -----------------------------------------------------------------
   
      fs= ybot/6 ;
   
      gdImageStringTTF( im, brect,             // imagespace, bounding box
                       white , FNT, fs, 0.0,   // color, font, fontsize, angle
                       15     , fs+15  ,       //  x, y
                       "Dish Antenna" );       //  text
   
// draw dish --------------------------------------------------------------
   
      jcolor    = bcolor[255] ;
   
      // disk
      gdImageFilledEllipse( im, oxc, ya,     4*cir,  cir,   jcolor );
   
      //  square feed 
      beam[0].x = oxc+6     ;
      beam[0].y = ya+cir-1  ;
      beam[1].x = oxc-6     ;
      beam[1].y = ya+cir-1  ;
      beam[2].x = oxc-6     ;
      beam[2].y = ya+cir+15 ;
      beam[3].x = oxc+6     ;
      beam[3].y = ya+cir+15 ;
   
      gdImageFilledPolygon( im, beam, 4,             jcolor );
   
      // feed struts
      gdImageLine( im, oxc-2*cir, ya, oxc,  ya+cir,  jcolor );
      gdImageLine( im, oxc+2*cir, ya, oxc,  ya+cir,  jcolor );
      gdImageLine( im, oxc,       ya, oxc,  ya+cir,  jcolor );

   
      // labels on array -------------------------------------------------------
      fs= ybot/8 ;
   
      gdImageStringTTF( im, brect,             // imagespace, bounding box
                       white , FNT, fs, 0.0,   // color, font, fontsize, angle
                       15, YSIZE-15,           //  x, y
		       "Ground Pattern" );     //  text
   
      // output the frame ------------------------------------------------------
   
      sprintf( framename, PNGFMT , frame );
      pngout = fopen( framename, "wb");
      gdImagePngEx( im, pngout, 1 );

      gdImageDestroy(im);
      fclose(pngout);
   
   }  // end of single frame loop

   printf( "frames complete, now run\n");
   printf( "%s\n", PNG2APNG );
}
   
   
