// phased array, 7x7
//
// compile with:       cc -o pa03 pa03.c -lgd -lpng -lm
//
// 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.  If you don't have them, you can
// copy ../fonts/truetype/.. from openoffice.org to /usr/share/
//
// Uses swftools to build a swf movie from individual png images
//        for more information, see http://www.swftools.org/
//
// This constructs half the slides, then mirrors them

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

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

#define  YCENT       130
#define  WAVELENGTH  104.0        // radio wavelength in pixel units
#define  SPACE       40.0         // array spacing in pixel units
#define  NPICS       40           // the number of frames

#define  TANG        0.0          // target angle in degrees

#define  SPOT        16           // size of drawn spot
#define  ASIZE       7            // number of elements per side
#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

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

int main() {

   gdImagePtr im                    ; // pixel image map used by gd
   double   space  = (double) SPACE ; // nominal spacing between server-sats
   double   yacent = (double) YCENT ; // center of array drawing
   double   xsize  = (double) XSIZE ; // width of pixels
   double   ysize  = (double) YSIZE ; // height of pixels
   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    = YCENT          ; // center of output pixel array
   int      ybot   = 2*YCENT        ; //
   double   xacent = (double) oxc   ; // real ""
   double   k     = pi2/WAVELENGTH  ; // wavenumber
   FILE     *pngout                 ; // file handle for PNG output frame
   char     dirname[80]             ; // frame output directory
   char     framename[80]           ; // directory/name of frame
   char     labstring[80]           ; // used for labelling
   char     link0[80]               ; // directory/name of source
   char     link1[80]               ; // directory/name of target hardlink
   int      black, sun1, white, red ; // color map numbers
   int      green, blue, gray       ; // color map numbers
   int      dgray, trans, olp, olm  ; // color map numbers
   int      gcolor[256]             ; // color map numbers
   double   ax[ASIZE][ASIZE]        ; // x position of element
   double   ay[ASIZE][ASIZE]        ; // y position of element
   double   ap[ASIZE][ASIZE]        ; // phase of element
   double   xx, yy                  ; //
   int      ix, iy                  ; // integer counters
   int      ox, oy                  ; // output pixel position
   int      i                       ; // general counter
   int      fs                      ; // big label font size
   int      icolor                  ; //
   int      cir                     ; //
   int      mag                     ; // pixel magnitude, 0-255
   double   ss                      ; // summed sin component
   double   phase                   ; // phase
   double   gphase                  ; // global time phase
   double   axx                     ;
   double   sxx                     ;
   double   stang=sin(d2r*TANG)     ;
   double   ctang=cos(d2r*TANG)     ;
   int      frame                   ; // animation frame count
   int      pct=0                   ; // percentage of complete frame
   int      pct0=0                  ; // previous percentage
   double   dis                     ; 
   double   ffrac                   ; // frame fraction, 0 to 1
   int      asize = ASIZE           ; // nominal spacing of server-sats
   int      asize2 = asize*asize    ; //
   double   offset=0.5*(1.0-asize)  ; // offsets counter integer to center
   double   norm                    ; // normalize

   norm=1.0/(double)asize2          ; // normalize

//  set up target directory

   system( RMMKDIR );

//  define array with even spacing ---------------------------------------

   for( iy=0; iy<asize ; iy++ ) {
      yy = space*(((double)iy)+offset) ;
      for( ix=0; ix<asize ; ix++ ) {
         // compute array positions
         xx = space*(((double)ix)+offset) ;
         ax[ix][iy] = xx+xacent ;
         ay[ix][iy] = yy+yacent ;
         ap[ix][iy] = k*(ctang*yy+stang*xx) ;
      }
   }

#ifdef DEBUG
   for( iy=0; iy<asize ; iy++ ) {
      for( ix=0; ix<asize ; ix++ ) {
         printf( "%2d%2d%10.2f%10.2f%10.4f\n",
                 ix,iy, ax[ix][iy], ay[ix][iy], ap[ix][iy] );
      }
   }
#endif

//  outer loop, sinusodial random factor change --------------------------
//  from 0 to 1 to 0

   for( frame=0 ; frame<NPICS ; frame++ ) {
      
      ffrac  = ((double)frame)/((double)NPICS);
      gphase = pi2*ffrac ;

// 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);
      olm   = gdImageColorAllocate(im,  32,   0,   0);
      olp   = gdImageColorAllocate(im, 255, 224, 224);
      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, 128, 128, 128);
      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);
      }

//   now compute phases

      for( ox=0 ; ox<XSIZE ; ox++ ) {
         pct0  = pct ;
         pct   = (100*ox)/XSIZE ;

#ifndef SINGLE
         if( pct != pct0 ) {
            printf( "%04d/%04d%4d\r", frame, NPICS, pct ) ;
            fflush(stdout);
	 }
#endif
	 for( oy=0 ; oy<YSIZE ; oy++ ) {

            ss = 0.0 ;                  // sum the components

            // compute z distance and phase of each source to plane
            for( iy=0; iy<asize ; iy++ ) {
               for( ix=0; ix<asize ; ix++ ) {
                  yy = (double) (oy-ay[ix][iy]);
                  xx = (double) (ox-ax[ix][iy]);
                  dis = sqrt( xx*xx+yy*yy ) ;
                  if( dis > 0.9 ) {
                      // not inverse square!!!
                      axx = -gphase + ap[ix][iy] + k*dis ;
                      sxx = sin( axx );
                      ss += sxx ;
                  } else {

#ifdef DEBUG
                      printf( "%6d%4d", ox, oy );
#endif
                  }

#ifdef DEBUG
                  if( (oy==384) && (ox==512) ) {
                     printf(
                       "%2d%2d %7.0f%7.0f%10.4f %10.4f%10.4f%10.4f%10.4f\n",
                               ix,iy,  xx,   yy,  sxx,
                               axx, ap[ix][iy],  k, dis );
		  }
#endif
            }  }

            mag = (int)( 127.0*(1.0+norm*ss ) );

#ifdef DEBUG
            if( ( oy == 384 ) && (ox == 512 ) ) {
               printf( "%4d%4d%13.4f%13.4f%12d\n", ox, oy, ss, gphase, mag );
            }
            printf("%5d",mag );
#endif

            if( mag < 0 ) {
               gdImageSetPixel( im, ox, oy, olm         ) ;
            }
            else if( mag > 255 ) {
               gdImageSetPixel( im, ox, oy, olp         ) ;
            }
            else {
               gdImageSetPixel( im, ox, oy, gcolor[mag] ) ;
            }
      }  }

#ifdef DEBUG
      printf("\n%4d\n", frame);
#endif

// Slide Label ----------------------------------------------------------

      fs= ybot/8 ;
      gdImageStringFT( im, NULL,            // imagespace, bounding box
                    white , FNT, fs, 0.0,   // color, font, fontsize, angle
                    15     , fs+15  ,       //  x, y
                    "Phased Array" );       //  text

// draw array ------------------------------------------------------------

      for( iy=0; iy<asize ; iy++ ) {
         for( ix=0; ix<asize ; ix++ ) {
            ox     = (int) ax[ix][iy] ;
            oy     = (int) ay[ix][iy] ;
            cir    = SPOT+6 ;
            gdImageFilledEllipse(im, ox, oy, cir, cir, black          );

            cir    = SPOT ;
	    icolor = (int) ( 127.0*(1.0+0.9*sin(gphase+ap[ix][iy] ) ) ) ;
            gdImageFilledEllipse(im, ox, oy, cir, cir, gcolor[icolor] );
      }  }

// output the frame ------------------------------------------------------

      sprintf( framename, PNGFMT , frame );
      pngout = fopen( framename, "wb");
      gdImagePngEx( im, pngout, 1 );
      gdImageDestroy(im);
      fclose(pngout);

   }  // end of single frame

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