/* ***********************************************************************
 * *                                                                     *
 * *  Function to convert an ASCII file to an IRIS WARN product          *
 * *                                                                     *
 * ***********************************************************************
 * File: utils/pipes_in/AsciiToPlane.C
 *
 *                      COPYRIGHT (c) 2002, 2003  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

/* This program is a pipe which takes an input ASCII file defining the plane 
 * data  and converts it into an IRIS WARN product containing
 * that data.
 *
 * Note if you are modifying this program, and wish to insert a diagnostic
 * printf, be sure to write it to the error output.
 */

#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "sigtypes.h"
#include "projection.h"
#include "setup.h"
#include "headers.h"
#include "iris_task.h"
#include "product.h"
#include "dsp_lib.h"
#include "himath_lib.h"
#include "misc_lib.h"
#include "user_lib.h"

/**************************************************************
**
** The Ascii input file description.
** The format is pretty simple.  There will be five fields per line, comma
** delimited.  The first field will be a two-character description of the 
** target.  The next two fields are the 
** latitude and longitude respectively, in floating point format.  This is 
** followed by the altitude in signed integer format.  The final field is 
** the date and time, in YYYYMMDDHHMMSS format.
** 
** We will be tracking six aircraft, so there will be generally six lines 
** of information.  However, if one aircraft's position is missed, or the 
** data is bad, the remaining data will be written to the file, so the 
** number of lines may be less than six in some cases.

** Date Format
** Target,Latitude,Longitude,Altitude,Date and Time

Example Data:
** t1,25.64753588,80.50522714,5000,20020625143131
** t2,25.65043163,80.50265758,5010,20020625143131
** t3,25.65084536,80.50329694,5200,20020625143131
** t4,25.64992021,80.50901267,5050,20020625143131
** t5,25.6493381,80.50947109,5007,20020625143131
** t6,25.64799908,80.51002374,54300,20020625143135
**
*********************************************************************/

/* This holds information to customize the convertor */
struct projection_summary
{
  BIN4  iRadarLat;                  /* Latitude of the radar */
  BIN4  iRadarLon;                  /* Longitude */
  FLT8  fRMax;                      /* Range from center to right side of screen */
  BIN4  iCenterLat;                 /* Latitude of center of product */
  BIN4  iCenterLon;                 /* Longitude */
  UINT1 iType;                      /* Type of projection */
  BIN4  iReferenceLat;              /* Latitude of reference point */
  BIN4  iReferenceLon;              /* Longitude */
  SINT4 iXSize, iYSize;             /* Sizes in pixels */
  SINT4 iXScale, iYScale;           /* Scales in cm/pixel */
  SINT4 iXRadPos, iYRadPos;         /* Radar positions in 1/1000 of pixels */
};

#define MAX_SKIP_NAMES (16)
struct convert_config
{
  UINT1  lLogToFile;
  UINT1  lLogToTerm;
  UINT1  lVerbose;              /* Log more details */
  FILE   *iLogFile;             /* Open file descriptor to log file */
  char   sIngSitename[16];      /* Ingest sitename to use, space padded */
  struct projection_summary Projection;
};
struct convert_config CSetup_c;

/* Local function prototypes
 */
static void  InitializeProdHeader(struct product_hdr *ProdHeader_a, 
  const struct projection_summary *pProjSum_a);
static UINT1 lProcessAsciiLine (char *sptr_a, struct warn_product *pWarnProduct_a,
  UINT1 lfirstpass_a);
static void  ProcessCommandLine (int iArgc, char *sArgv[]);
static void  Usage( void );
static void  LoadSetup(struct convert_config *pCSetup_a );
static UINT2 ProcessConfigLine(char *sline_a, struct convert_config *pCSetup_a );
static void  Lprintf(const char *sString_a);
static void FillProjectionNumbers(struct projection_summary *pProj_a );

#define MAX_LINELENGTH (120)
/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  int    total_bytes;  
  UINT1  lfirstpass;
  struct warn_product warnProduct;
  SINT4  iLine ;
  char   sLog[200], sLine[MAX_LINELENGTH], *sptr;

  setlocale( LC_ALL, "" ) ;

  memset( &warnProduct, 0, sizeof(struct warn_product));

  /* Process the command line arguments */
  ProcessCommandLine( iArgc, sArgv );

  /* Process the setup file,if any.  ** We're using:
  **  /usr/sigmet/config/AsciiToPlane.conf */
  LoadSetup(&CSetup_c);

  /* Open the logging file, if any */
  if (CSetup_c.lLogToFile)
    {
      char *sptr;
      char sLogPath[PATHNAME_SIZE];
      sptr = getenv( "IRIS_LOG" );
      if (sptr)
	{
	  strncpy( sLogPath, sptr, PATHNAME_SIZE-20 );
	  sLogPath[PATHNAME_SIZE-20] = 0;
	}
      else
	strcpy( sLogPath, "/tmp/" );
      strcat( sLogPath, "AsciiToPlane.log" );
      CSetup_c.iLogFile = fopen( sLogPath, "w" );
      if (NULL == CSetup_c.iLogFile)
	{
	  fprintf( stderr, "Can not open log file: '%s'\n", sLogPath );
	  exit(EXIT_FAILURE);
	}
    }

  /* Starting here we can use the Lprintf function */
  if (CSetup_c.lVerbose)
     Lprintf( "Verbose Logging On.\n");
    
  /* Read in the header */
  InitializeProdHeader(&warnProduct.Header, &CSetup_c.Projection);

  /* now loop through the file reading and parsing lines from the standard input */
  iLine = 1;
  lfirstpass = TRUE;
  sptr = fgets( sLine, MAX_LINELENGTH, stdin );
  while (NULL != sptr)
    {
      UINT1 lerror;
      if (CSetup_c.lVerbose)
	{
	  sprintf( sLog, "Line %d: %s", iLine, sptr );
	  Lprintf( sLog);
	}
      lerror = lProcessAsciiLine( sptr, &warnProduct, lfirstpass);
      if (lerror)
	{
	  sprintf( sLog, "Syntax error on ASCII file line %d\n", iLine );
	  Lprintf( sLog );
	}
      iLine +=1;
      sptr = fgets( sLine, MAX_LINELENGTH, stdin );
      lfirstpass = FALSE;
    }

  total_bytes = PRODUCT_HDR_SIZE + sizeof(struct protect_setup) +
    warnProduct.Header.end.iresults_count*sizeof(struct warning_results);

  warnProduct.Header.hdr.ibytes = total_bytes; 

  /* Write out the results to the standard output */
  fwrite( &warnProduct, sizeof(struct warn_product), 1, stdout );

  if (CSetup_c.lVerbose)
    {
      sprintf( sLog, "Wrote %d bytes, %d warnings\n", total_bytes,
	       warnProduct.Header.end.iresults_count );
      Lprintf( sLog);
    }
  exit( EXIT_SUCCESS );
}
/* ===============================================
 * Fill in the product header.
 */
static void InitializeProdHeader(struct product_hdr *pProdHeader_a, const struct projection_summary *pProjSum_a)
{
  int ii;
  HeaderFromScratch( pProdHeader_a, NULL, CSetup_c.sIngSitename,
		     CSetup_c.sIngSitename, "PLANE" );
  pProdHeader_a->pcf.iptype    = PROD_WARN;

  pProdHeader_a->pcf.ixscale   = pProjSum_a->iXScale;
  pProdHeader_a->pcf.iyscale   = pProjSum_a->iYScale;
  pProdHeader_a->pcf.izscale   = 0;
  pProdHeader_a->pcf.ixsize    = pProjSum_a->iXSize;
  pProdHeader_a->pcf.iysize    = pProjSum_a->iYSize;
  pProdHeader_a->pcf.izsize    = 1;
  pProdHeader_a->pcf.ixrad     = pProjSum_a->iXRadPos;
  pProdHeader_a->pcf.iyrad     = pProjSum_a->iYRadPos;
  pProdHeader_a->pcf.izrad     = 0;

  pProdHeader_a->pcf.idata_out = DB_NULL;
  
  for (ii = 0; ii <= WARN_MAX_INPUTS; ii++)
     pProdHeader_a->pcf.psi.warn.iwarn_prods[ii] = PROD_WARN;

  pProdHeader_a->pcf.iprojection_type = pProjSum_a->iType;

  pProdHeader_a->end.ilat_center = pProjSum_a->iCenterLat;
  pProdHeader_a->end.ilon_center = pProjSum_a->iCenterLon;

  pProdHeader_a->end.ilat_ref = pProjSum_a->iReferenceLat;
  pProdHeader_a->end.ilon_ref = pProjSum_a->iReferenceLon;
}

/* ===============================================
 * Process on line of the input data.
 */
static UINT1 lProcessAsciiLine
( char *sline_a,
  struct warn_product *pWarnProduct_a,   /* Pointer will be updated */
  UINT1 lfirstpass_a)
{
   UINT2 lfound_digit;
   UINT4 ii;
   SINT4 ihgt;
   SINT4 id;
   SINT4 iCount, iYear, iMonth, iDay, iHour, iMinute, iSec;
   SINT4 idx;
   SINT4 icnt;
   SINT4 itokcnt;
   FLT8  fpos;
   char  *sptr;
   char  snum[20], starget[20], slat[20], slon[20], shgt[20], sdate[20]; 
   struct ymds_time Time;

   if (lfirstpass_a)
      pWarnProduct_a->Header.end.iresults_count = 0;
   itokcnt = 0;
   starget[0] = '\0';
   slat[0] = '\0'; 
   slon[0] = '\0'; 
   shgt[0] = '\0'; 
   sdate[0] = '\0'; 
   sptr = strtok(sline_a, ",");
   while(sptr != NULL)
   {
      switch(itokcnt)
      {
         case 0 : strncpy(starget, sptr, 20);starget[19]='\0';break;
         case 1 : strncpy(slat, sptr, 20);slat[19]='\0';break;
         case 2 : strncpy(slon, sptr, 20);slon[19]='\0';break;
         case 3 : strncpy(shgt, sptr, 20);shgt[19]='\0'; break;
         case 4 : strncpy(sdate, sptr, 20);sdate[19]='\0';break;
      }
      sptr = strtok(NULL, ",");
      itokcnt++;
   }
   if (itokcnt < 5) 
   {
      fprintf( stderr, "Not enough parameters\n");
      return  TRUE;
   }
   else if (itokcnt > 5) 
   {
      fprintf( stderr, "To many parameters\n");
      return  TRUE;
   }
   
   icnt = pWarnProduct_a->Header.end.iresults_count;

   /* Parse out of the target string, a number that we
   ** can use  as the id number.
   */
   idx = 0;
   lfound_digit = false;
   for (ii = 0; ii < strlen(starget); ii++)
   {
      if (isdigit(starget[ii]))
      {
         snum[idx++] =  starget[ii];
         lfound_digit = true;
      }
      else 
      {
        if (lfound_digit)
           break;
      }
   }
   snum[idx] = '\0';

   id = strtol(snum, &sptr, 10);
   if (snum == sptr) return TRUE;
   pWarnProduct_a->Results[icnt].iaverage_value[0] = id * 100; 
   pWarnProduct_a->Results[icnt].iaverage_value[1] = id * 100; 
   pWarnProduct_a->Results[icnt].iaverage_value[2] = id * 100; 
   pWarnProduct_a->Results[icnt].imax_value[0] = id * 100; 
   pWarnProduct_a->Results[icnt].imax_value[1] = id * 100; 
   pWarnProduct_a->Results[icnt].imax_value[2] = id * 100; 
   strcpy(pWarnProduct_a->Results[icnt].stext, "dot13");

/*
   strncpy(pWarnProduct_a->Results[icnt].stext, starget, 16);
   pWarnProduct_a->Results[icnt].stext[15] = '\0';
*/

   fpos = strtod( slat, &sptr);
   if (slat==sptr) return TRUE;
   if ((fpos < -90.0)||(fpos > 90.0)) return TRUE;
   pWarnProduct_a->Results[icnt].ilatitude = iBin4FromFDeg( fpos );

   fpos = strtod( slon, &sptr);
   if (slon==sptr) return TRUE;
   if ((fpos < -180.0)||(fpos > 180.0)) return TRUE;
   pWarnProduct_a->Results[icnt].ilongitude = iBin4FromFDeg( fpos );

   ihgt = strtol(shgt, &sptr, 10);
   if (shgt == sptr) return TRUE;
   pWarnProduct_a->Results[icnt].iheight = ihgt * 10000;

   memset( &Time, 0, sizeof(Time) );
   iCount = sscanf( sdate, "%4d%2d%2d%2d%2d%2d", &iYear, &iMonth, &iDay,
         &iHour, &iMinute, &iSec );
   if (iCount<6) return TRUE;

   Time.iyear = iYear;
   Time.imon = iMonth;
   Time.iday = iDay;
   Time.isec = iPackTime( iHour, iMinute, iSec );
   if (Time.iyear<1950) return TRUE;
   if (Time.iyear>3000) return TRUE;
   if (Time.imon<1) return TRUE;
   if (Time.imon>12) return TRUE;
   if (Time.iday<1) return TRUE;
   if (Time.iday>31) return TRUE;
   if (Time.isec>1+24*3600) return TRUE;

   pWarnProduct_a->Header.pcf.ing_time = Time;
   pWarnProduct_a->Header.pcf.epoch = Time;

/* Added for testing
   fprintf(stderr, "LINE %d tgt <%s> num <%s> lat <%s> lon <%s> hgt <%s> sdate <%s>\n", 
     icnt, starget, snum, slat, slon, shgt, sdate);
*/
   pWarnProduct_a->Header.end.iresults_count++;

  return FALSE;
}
/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[] )
{

  int iArg;

  /* Parse command line options
   */
  for( iArg=1 ; iArg<iArgc_a ; iArg++ )
    {
      const char *sArg = sArgv_a[iArg];
      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */

      if (0 == strncmp( sArg, "-h", 2 ))
	{
	  Usage();
	}
      
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: -help\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
  exit(EXIT_FAILURE) ;
}

/* ============================================================
 * Function to load the convert setup from a configuration file.
 */
static void LoadSetup( struct convert_config *pCSetup_a )
{
  char sPath[PATHNAME_SIZE];
  char sline[81], *sptr;
  FILE* stream;
  SINT4 iline;
  UINT2 lerror;

  /* Initialize the data to the default values */
  memset( pCSetup_a, 0, sizeof(*pCSetup_a) );
  spacify_ncpy( pCSetup_a->sIngSitename, "UNKNOWN", 16 );
  /* Default location is 0 0 latlon, AED, max range=100 km */
  pCSetup_a->Projection.fRMax = 100.0;
  pCSetup_a->Projection.iType = MAPROJ_AZIMUTHAL;
  pCSetup_a->Projection.iXSize = 480;
  
  /* Generate the file name and open the file */
  sptr = getenv( "IRIS_CONFIG" );
  if (NULL == sptr) 
    {
      sig_signal_va( USER_NO_ENV, 1, "IRIS_CONFIG" );
      exit(EXIT_FAILURE);
    }

  strncpy( sPath, sptr, 140 );
  strcat( sPath, "AsciiToPlane.conf" );
  stream = fopen( sPath, "r" );

  /* Don't worry about a missing config file */
  if (NULL == stream) return;

  /* now loop through the file reading and parsing lines */
  iline = 1;
  sptr = fgets( sline, 81, stream );
  while (NULL != sptr)
    {
      lerror = ProcessConfigLine( sptr, pCSetup_a );
      if (lerror) fprintf( stderr, "Syntax error on config file line %d\n", iline );
      iline +=1;
      sptr = fgets( sline, 81, stream );
    }

  fclose( stream );

  FillProjectionNumbers( &pCSetup_a->Projection );
  return;
}

/* ===============================================================
 * Process one line from the configuration file.  Returns nonzero if there
 * is a syntax error.
 *
 * The config can contain the following commands.  All blank lines and
 * lines beginning with "#" are ignored.  Commands can be in any order.
 * Commands take effect in the order received.  For example, syntax errors
 * before the LOG command will not be logged.
 *
 * LOG           <FILE TERM BOTH NONE>
 * SITENAME      <name>
 * VERBOSE
 *
 */
static UINT2 ProcessConfigLine
(char *sline_a,
 struct convert_config *pConfig_a )
{
  char *stokens[9], *sptr;
  UINT4 icount, ioffset;
  
  ioffset = 0;
  icount  = 0;
  /* Process up to 9 tokens, stop when the line is exhausted. */
  while (icount<9) 
    {
      stokens[icount] = sigtok( sline_a, &ioffset );
      if (NULL == stokens[icount])
	break;
      else
	icount++;
    }
  
  /* Blank lines are allowed and skipped */
  if (icount == 0) return FALSE;
  
  /* Skip commented lines */
  if (stokens[0][0] == '#') return FALSE;


  /* See if the line contains the CENTER_LATLON command */
  if ( 0 == strcmp( "CENTER_LATLON", stokens[0] ) )
    {
      FLT8 fLatitude, fLongitude;
      if ( icount < 3 ) return TRUE;
      
      fLatitude = strtod( stokens[1], &sptr );
      if (sptr == stokens[1]) return TRUE;

      fLongitude = strtod( stokens[2], &sptr );
      if (sptr == stokens[2]) return TRUE;

      if (fLatitude  <  -90.0 ) return TRUE;
      if (fLatitude  >   90.0 ) return TRUE;
      if (fLongitude < -180.0 ) return TRUE;
      if (fLongitude >  180.0 ) return TRUE;

      pConfig_a->Projection.iCenterLat = iBin4FromFDeg(fLatitude);
      pConfig_a->Projection.iCenterLon = iBin4FromFDeg(fLongitude);
      return FALSE;
    }

  /* See if the line contains the LOG file command */
  if ( 0 == strcmp( "LOG", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      if      ( 0 == strcmp( "BOTH", stokens[1] ) ) 
	{pConfig_a->lLogToFile=TRUE;  pConfig_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "FILE", stokens[1] ) ) 
	{pConfig_a->lLogToFile=TRUE;  pConfig_a->lLogToTerm=FALSE;}
      else if ( 0 == strcmp( "TERM", stokens[1] ) )
	{pConfig_a->lLogToFile=FALSE; pConfig_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "NONE", stokens[1] ) )
	{pConfig_a->lLogToFile=FALSE; pConfig_a->lLogToTerm=FALSE;}
      else
	return TRUE;
      return FALSE;
    }

  /* See if the line contains the MAX_RANGE command */
  if ( 0 == strcmp( "MAX_RANGE", stokens[0] ) )
    {
      FLT8 fRMax;
      if ( icount < 2 ) return TRUE;
      
      fRMax = strtod( stokens[1], &sptr );
      if (sptr == stokens[1]) return TRUE;

      if (fRMax <    1.0 ) return TRUE;
      if (fRMax > 1000.0 ) return TRUE;

      pConfig_a->Projection.fRMax = fRMax;
      return FALSE;
    }

  /* See if the line contains the PROJECTION file command */
  if ( 0 == strcmp( "PROJECTION", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      pConfig_a->Projection.iType = iProjectionFromName16( stokens[1] );
      if (pConfig_a->Projection.iType >= MAPROJ_COUNT ) return TRUE;
      return FALSE;      
    }

  /* See if the line contains the RADAR_LATLON command */
  if ( 0 == strcmp( "RADAR_LATLON", stokens[0] ) )
    {
      FLT8 fLatitude, fLongitude;
      if ( icount < 3 ) return TRUE;
      
      fLatitude = strtod( stokens[1], &sptr );
      if (sptr == stokens[1]) return TRUE;

      fLongitude = strtod( stokens[2], &sptr );
      if (sptr == stokens[2]) return TRUE;

      if (fLatitude  <  -90.0 ) return TRUE;
      if (fLatitude  >   90.0 ) return TRUE;
      if (fLongitude < -180.0 ) return TRUE;
      if (fLongitude >  180.0 ) return TRUE;

      pConfig_a->Projection.iRadarLat = iBin4FromFDeg(fLatitude);
      pConfig_a->Projection.iRadarLon = iBin4FromFDeg(fLongitude);
      return FALSE;
    }

  /* See if the line contains the SITENAME command */
  if ( 0 == strcmp( "SITENAME", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      spacify_ncpy( pConfig_a->sIngSitename, stokens[1], 16 );
      return FALSE;
    }
  
  
  if ( 0 == strcmp( "VERBOSE", stokens[0] ) )
    {
      pConfig_a->lVerbose = TRUE;
      return FALSE;
    }

  if ( 0 == strcmp( "X_SIZE", stokens[0] ) )
    {
      SINT4 iXSize;
      if ( icount < 2 ) return TRUE;
      iXSize = strtol( stokens[1], &sptr, 10 );
      /* Invalid parse is detected here */
      if (iXSize<MIN_PRODUCT_SIZE) return TRUE;
      if (iXSize>MAX_PRODUCT_SIZE) return TRUE;
      pConfig_a->Projection.iXSize = iXSize;
      return FALSE;
    }
  
  /* Unrecognized lines will generate a syntax error */
  return TRUE;
}

/* ===========================================
 * Print string to log and terminal, if desired.
 */
static void Lprintf
( const char *sString_a )
{
  if (CSetup_c.lLogToTerm) fputs( sString_a, stderr );
  if (CSetup_c.lLogToFile)
    {
      fputs( sString_a, CSetup_c.iLogFile );
      fflush( CSetup_c.iLogFile );
    }
}


/* ===============================================
 * Fill in the radar position in pixels*1000, etc., from other information
 * in the setup file.
 */
static void FillProjectionNumbers
( struct projection_summary *pProj_a )
{ 
  MESSAGE istatus;
  struct mpj_projection8 mpj;
  struct mpj_region8     region;

  /* As a default, set reference to center */
  pProj_a->iReferenceLat = pProj_a->iCenterLat;
  pProj_a->iReferenceLon = pProj_a->iCenterLon;

  /* Initialize outputs in case of an error return
   */
  pProj_a->iXRadPos = 0;
  pProj_a->iYRadPos = 0;
  pProj_a->iYSize  = pProj_a->iXSize;
  pProj_a->iXScale = 100000;
  pProj_a->iYScale = 100000;

  mpj.iprojection_type = pProj_a->iType;
  mpj.Ref.fLat         = fRadianFromBin4( pProj_a->iReferenceLat );
  mpj.Ref.fLon         = fRadianFromBin4( pProj_a->iReferenceLon );

  region.Loc1.fLat = fRadianFromBin4( pProj_a->iCenterLat );
  region.Loc1.fLon = fRadianFromBin4( pProj_a->iCenterLon );
  region.fde  = pProj_a->fRMax;
  region.fdn  = pProj_a->fRMax;
  region.fxpix = (FLT8)pProj_a->iXSize;
  istatus = mpj_pin_region( &mpj, &region, MPJ_LOC1|MPJ_FDE|MPJ_FDN );
  if (istatus != SS_NORMAL)
    {
      sig_signal( istatus );
      return;
    }

  /* Fill in the final X & Y sizes and scales
   */
  pProj_a->iXSize  = NINT( region.fxpix );
  pProj_a->iYSize  = NINT( region.fypix );
  pProj_a->iXScale = NINT( 200000.0*region.fde/region.fxpix);
  pProj_a->iYScale = NINT( 200000.0*region.fdn/region.fypix);
  
  /* Fill in the radar location in fractional pixels within the
   * data array.  If pointer is NULL, then use the center.
   */
  {
    struct latlon8 RadarEarth;
    struct XYPoint8 Pix; UINT1 lValid;
    RadarEarth.fLat = fRadianFromBin4( pProj_a->iRadarLat ) ;
    RadarEarth.fLon = fRadianFromBin4( pProj_a->iRadarLon ) ;
    
    mpj_earth_to_pixel( &mpj, &region, &RadarEarth, &Pix, &lValid ) ;
    
    pProj_a->iXRadPos = NINT( 1000.0 * Pix.fX ) ;
    pProj_a->iYRadPos = NINT( 1000.0 * Pix.fY ) ;
  }
  return;
}
