Beispiel #1
0
int CScntv2Q (struct csGeodeticXfromParmsFile_* fileParms,Const char* dictDir,int err_list [],int list_sz)
{
	extern char cs_DirsepC;

	int err_cnt;
	size_t rdCnt;

	char *cp;
	csFILE* strm;

	char chrBuffer [16];
	char pathBuffer [MAXPATH];

	cp = fileParms->fileName;
	if (*cp == '.' && *(cp + 1) == cs_DirsepC)
	{
		CS_stncp (pathBuffer,dictDir,sizeof (pathBuffer));
		CS_stncat (pathBuffer,cp,MAXPATH);
	}
	else
	{
		CS_stncp (pathBuffer,cp,MAXPATH);
	}

	/* We will return (err_cnt + 1) below. */
	err_cnt = -1;
	if (err_list == NULL) list_sz = 0;

	/* Verify that the file exists and that the format appears to be correct. */
	strm = CS_fopen (pathBuffer,_STRM_BINRD);
	if (strm != NULL)
	{
		rdCnt = CS_fread (chrBuffer,1,sizeof (chrBuffer),strm);
		CS_fclose (strm);
		strm = NULL;

		if (rdCnt != sizeof (chrBuffer) || CS_strnicmp (chrBuffer,"NUM_OREC",8))
		{
			if (++err_cnt < list_sz) err_list [err_cnt] = cs_DTQ_FORMAT;
		}
	}
	else
	{
		if (++err_cnt < list_sz) err_list [err_cnt] = cs_DTQ_FILE;
	}
	return (err_cnt + 1);
}
Beispiel #2
0
int EXP_LVL9 CSdtcomp (	Const char *inpt,
						Const char *outp,
						int flags,
						Const char *elipsoid,
						int (*err_func)(char *mesg)
					  )
{
	int st;
	int test;
	int demo;
	int warn;
	int dummy;
	int cancel;
	int err_cnt;
	int crypt;

	size_t rdCnt;
	size_t wrCnt;

	char *cp;
	csFILE *inStrm;
	csFILE *elStrm;
	csFILE *outStrm;
	struct cs_DtcmpT_ *tp;
	struct cs_DtTypeT_ *typPtr;

	cs_magic_t magic;

	char err_seg [18];
	char buff [128];
	char err_msg [128];
	char last_name [48];

	__ALIGNMENT__2		/* For some versions of Sun compiler. */
	struct cs_Dtdef_ dtdef;

	crypt = ((flags & cs_CMPLR_CRYPT) != 0);
	demo  = ((flags & cs_CMPLR_DEMO) != 0);
	test  = ((flags & cs_CMPLR_TEST) != 0);
	warn  = ((flags & cs_CMPLR_WARN) != 0);

	/* Open the source file. */
	inStrm = CS_fopen (inpt,_STRM_TXTRD);
	if (inStrm == NULL)
	{
		sprintf (err_msg,"Couldn't open %s for input.",inpt);
		cancel = (*err_func)(err_msg);
		return (1);
	}

	/* Open the output file and write the magic number.  BINRW mode
	   creates a new file with read and write access. */
	outStrm = CS_fopen (outp,_STRM_BINRW);
	if (outStrm == NULL)
	{
		sprintf (err_msg,"Couldn't open %s for output.",outp);
		cancel = (*err_func)(err_msg);
		CS_fclose (inStrm);
		return (1);
	}
	if (demo) magic = cs_DTDEF_MAGIC;
	else      magic = cs_DTDEF_MAGIC;
	CS_bswap (&magic,"l");
	wrCnt = CS_fwrite ((char *)&magic,1,sizeof (magic),outStrm);
	if (wrCnt != sizeof (magic))
	{
		sprintf (err_msg,"Failure detected during write to %s.",outp);
		cancel = (*err_func)(err_msg);  
		CS_fclose (outStrm);
		CS_remove (outp);										/*lint !e534 */
		CS_fclose (inStrm);
		return (1);
	}

	/* If we have been given an ellipsoid file name, we open it now. */
	if (elipsoid != NULL && *elipsoid != '\0')
	{
		elStrm = CS_fopen (elipsoid,_STRM_BINRD);
		if (elStrm == NULL)
		{
			sprintf (err_msg,"Couldn't open %s as an Ellipsoid Dictionary.",elipsoid);
			cancel = (*err_func)(err_msg);
			CS_fclose (inStrm);
			return (1);
		}
		rdCnt = CS_fread (&magic,1,sizeof (magic),elStrm);
		CS_bswap (&magic,"l");
		if (rdCnt != sizeof (magic) ||
			(demo && magic != cs_ELDEF_MAGIC) ||
			(!demo && magic != cs_ELDEF_MAGIC))
		{
			sprintf (err_msg,"%s is not an Elipsoid Dictionary file.",elipsoid);
			cancel = (*err_func)(err_msg);
			CS_fclose (inStrm);
			CS_fclose (elStrm);
			return (1);
		}
	}
	else
	{
		elStrm = NULL;
	}

	/* Process each line in the source file. */
	line_nbr = 0;
	err_cnt = 0;
	cancel = FALSE;
	memset (&dtdef,'\0',sizeof (dtdef));
	dtdef.delta_X = no_value;
	dtdef.delta_Y = no_value;
	dtdef.delta_Z = no_value;
	dtdef.rot_X = no_value;
	dtdef.rot_Y = no_value;
	dtdef.rot_Z = no_value;
	dtdef.bwscale = no_value;
	dtdef.to84_via = cs_DTCTYP_NONE;
	while (CS_fgets (buff,sizeof (buff),inStrm) != NULL)
	{
		if (cancel)
		{
			CS_fclose (inStrm);
			CS_fclose (outStrm);
			if (elStrm != NULL) CS_fclose (elStrm);
			CS_remove (outp);										/*lint !e534 */
			return (err_cnt);
		}
		line_nbr += 1;

		/* Ignore comments and blank lines. */
		CS_trim (buff);
		if (buff [0] == '#' || buff [0] == '\0')
		{
			continue;
		}
		cp = buff;
		while ((cp = strchr (cp,'#')) != NULL)
		{
			if (*(cp + 1) != '#' &&
			    *(cp - 1) != '\\')
			{
				*cp = '\0';
				break;
			}
		}

		/* Run the line through the table parser.  We
		   see what type of line we have. */
		cp = buff;
		tp = (struct cs_DtcmpT_ *)CS_tpars (&cp,cs_DtcmpT,sizeof (struct cs_DtcmpT_));

		if (tp == NULL)
		{
			CS_stncp (err_seg,buff,sizeof (err_seg));
			sprintf (err_msg,"Invalid keyword (%s) on line %d.",err_seg,line_nbr);
			cancel = (*err_func)(err_msg);
			err_cnt += 1;
			dtdef.key_nm [0] = '\0';
			continue;
		}

		/* Here when we have a valid line. Cp points to the first
		   character after the colon. */
		CS_trim (cp);
		switch (tp->type) {
		case DT_NAME:

			/* Here each time we encounter a new datum
			   name.  We see if there is an existing
			   datum which must be written. */
			if (dtdef.key_nm [0] != '\0' &&		/* Skip 1st one. */
				(test || CS_stricmp (dtdef.group,"TEST")))
			{
				st = CSdtdefwr (outStrm,&dtdef,crypt,warn,elStrm,err_func);
				if (st >= 0) err_cnt += st;
				else
				{
					cancel = TRUE;
					err_cnt += -st;
				}
				
			}

			/* Prepare for the next coordinate system. */
			memset (&dtdef,'\0',sizeof (dtdef));
			dtdef.delta_X = no_value;
			dtdef.delta_Y = no_value;
			dtdef.delta_Z = no_value;
			dtdef.rot_X = no_value;
			dtdef.rot_Y = no_value;
			dtdef.rot_Z = no_value;
			dtdef.bwscale = no_value;
			dtdef.protect = FALSE;
			dtdef.to84_via = cs_DTCTYP_NONE;

			CS_stncp (dtdef.key_nm,cp,sizeof (dtdef.key_nm));
			st = CS_nampp (dtdef.key_nm);
			if (st != 0)
			{
				sprintf (err_msg,"%s is not a valid datum key name; line %d.",cp,line_nbr);
				cancel = (*err_func)(err_msg);
				err_cnt += 1;
			}
			break;

		case DESC_NM:
			if (strlen (cp) >= sizeof (dtdef.name) && warn)
			{
				sprintf (err_msg,"Warning: Description for %s on line %d is too long.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			CS_stncp (dtdef.name,cp,sizeof (dtdef.name));
			break;

		case ELLP_NM:
			CS_stncp (dtdef.ell_knm,cp,sizeof (dtdef.ell_knm));
			break;

		case LOCATION:
			if (strlen (cp) >= sizeof (dtdef.locatn) && warn)
			{
				sprintf (err_msg,"Warning: Country list for %s on line %d is too long.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			CS_stncp (dtdef.locatn,cp,sizeof (dtdef.locatn));
			break;

		case COUNTRY:
			if (strlen (cp) >= sizeof (dtdef.cntry_st) && warn)
			{
				sprintf (err_msg,"Warning: Country list for %s on line %d is too long.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			CS_stncp (dtdef.cntry_st,cp,sizeof (dtdef.cntry_st));
			break;

		case SOURCE:
			if (strlen (cp) >= sizeof (dtdef.source) && warn)
			{
				sprintf (err_msg,"Warning: Source for %s on line %d is too long.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			CS_stncp (dtdef.source,cp,sizeof (dtdef.source));
			break;

		case DELTA_X:
			dtdef.delta_X = atof (cp);
			if (warn && (fabs (dtdef.delta_X) > 2000.0))
			{
				sprintf (err_msg,"Warning: Delta X value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			break;

		case DELTA_Y:
			dtdef.delta_Y = atof (cp);
			if (warn && (fabs (dtdef.delta_Y) > 2000.0))
			{
				sprintf (err_msg,"Warning: Delta Y value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			break;

		case DELTA_Z:
			dtdef.delta_Z = atof (cp);
			if (warn && (fabs (dtdef.delta_Z) > 2000.0))
			{
				sprintf (err_msg,"Warning: Delta Z value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			break;

		case ROT_X:
			dtdef.rot_X = atof (cp);
			if (warn && (fabs (dtdef.rot_X) >= 60.0))
			{
				sprintf (err_msg,"Warning: X Rotation value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}		
			break;

		case ROT_Y:
			dtdef.rot_Y = atof (cp);
			if (warn && (fabs (dtdef.rot_Y) >= 60.0))
			{
				sprintf (err_msg,"Warning: Y Rotation value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}		
			break;

		case ROT_Z:
			dtdef.rot_Z = atof (cp);
			if (warn	 && (fabs (dtdef.rot_Z) >= 60.0))
			{
				sprintf (err_msg,"Warning: Y Rotation value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}		
			break;

		case BWSCALE:
			dtdef.bwscale = atof (cp);
			if (warn && (fabs (dtdef.bwscale) >= 25.0))
			{
				sprintf (err_msg,"Warning: Bursa Wolfe scale value for %s on line %d is suspicious.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}		
			break;

		case USE:
			dtdef.to84_via = cs_DTCTYP_NONE;
			for (typPtr = cs_DtTypeT;typPtr->type != cs_DTCTYP_NONE;typPtr += 1)
			{
				if (!CS_stricmp (cp,typPtr->label))
				{
					dtdef.to84_via = typPtr->type;
					break;
				}
			}
			if (dtdef.to84_via == cs_DTCTYP_NONE)
			{
				sprintf (err_msg,"Invalid 'USE' specification detected on line %d.",line_nbr);
				cancel = (*err_func)(err_msg);
				err_cnt += 1;
			}
			break;

		case GROUP:
			if (strlen (cp) >= sizeof (dtdef.group) && warn)
			{
				sprintf (err_msg,"Warning: Group for %s on line %d is too long.",dtdef.key_nm,line_nbr);
				cancel = (*err_func)(err_msg);
			}
			CS_stncp (dtdef.group,cp,sizeof (dtdef.group));
			break;

		case EPSG_NBR:
			dtdef.epsgNbr = atoi (cp);
			break;

		default:
			sprintf (err_msg,"Software problem detected at line %d in module %s.",__LINE__,__FILE__);
			(void)(*err_func)(err_msg);
			cancel = TRUE;
			break;
		}

		/* On to the next input line. */
	}
	CS_fclose (inStrm);

	/* Write out the last coordinate system if not in error. */
	if (dtdef.key_nm [0] != '\0' && (test || CS_stricmp (dtdef.group,"TEST")))
	{
		st = CSdtdefwr (outStrm,&dtdef,crypt,warn,elStrm,err_func);
		if (st >= 0) err_cnt += st;
		else
		{
			cancel = TRUE;
			err_cnt += -st;
		}
	}
	if (elStrm != NULL) CS_fclose (elStrm);
	if (cancel)
	{
		CS_fclose (outStrm);
		CS_remove (outp);										/*lint !e534 */
		return (err_cnt);
	}

	/* Sort the output file. */
	CS_fseek (outStrm,(long)sizeof (magic),SEEK_SET);
	CS_ips (outStrm,sizeof (dtdef),0L,(CMPFUNC_CAST)CS_dtcmp);		/*lint !e534 */

	/* Verify that there are no duplicates. */
	CS_fseek (outStrm,(long)sizeof (magic),0);
	CS_dtrd (outStrm,&dtdef,&dummy);								/*lint !e534 */
	CS_stncp (last_name,dtdef.key_nm,sizeof (last_name));
	while (!cancel && CS_dtrd (outStrm,&dtdef,&dummy) != 0)
	{
		if (!CS_stricmp (dtdef.key_nm,last_name))
		{
			sprintf (err_msg,"Datum key name %s appears more than once.",last_name);
			cancel = (*err_func)(err_msg);
			err_cnt += 1;
		}
		CS_stncp (last_name,dtdef.key_nm,sizeof (last_name));
	}
	CS_fclose (outStrm);

	/* Remove the output file if there were errors. */
	if (err_cnt != 0)
	{
		CS_remove (outp);										/*lint !e534 */
	}
	return (err_cnt);
}
Beispiel #3
0
/*****************************************************************************
	Constructor
*/
struct csGeoid99GridFile_* CSnewGeoid99GridFile (Const char *path,long32_t bufferSize,ulong32_t flags,double density)
{
	extern double cs_K360;
	extern char cs_DirsepC;
	extern char cs_ExtsepC;
	extern char csErrnam [];

	size_t readCount;
	long lngTmp;
	double lngMin, lngMax;
	char *cp1, *cp2;
	csFILE *fstr;
	struct csGeoid99GridFile_* __This;
	char cTemp [MAXPATH];
	struct csGeoid99Hdr_ geoid99Hdr;

	/* Prepare for an error. */
	__This = NULL;
	fstr = NULL;

	/* Malloc and initialize */
	__This = CS_malc (sizeof (struct csGeoid99GridFile_));
	if (__This == NULL)
	{
		CS_erpt (cs_NO_MEM);
		goto error;
	}
	CSinitGeoid99 (__This);

	/* Set default values for all members. */
	__This->bufferSize = bufferSize;
	if (__This->bufferSize < 0) __This->bufferSize = 0;

	/* Save file path/name. */
	CS_stncp (__This->filePath,path,sizeof (__This->filePath));
	CS_stncp (cTemp,path,sizeof (cTemp));

	/* Set up the type of file.  Get cp1 to point at the file
	   name, and cp2 to point at the extension.  We consider it
	   an error if we are not given a full path name.  Note,
	   we care not about the format of the drive specification.
	   But there must be at least one directory and there must
	   be an extension. */
	cp1 = strrchr (cTemp,cs_DirsepC);
	if (cp1 == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	cp1 += 1;
	cp2 = strchr (cp1,cs_ExtsepC);
	if (cp2 == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	*cp2++ = '\0';
	CS_stncp (__This->fileName,cp1,sizeof (__This->fileName));

	/* The thing should have a .bin extension to be processed by us. */
	if (CS_stricmp (cp2,"bin"))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Get the file information header. */
	fstr = CS_fopen (__This->filePath,_STRM_BINRD);
	if (fstr == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_DTC_FILE);
		goto error;
	}
	readCount = CS_fread (&geoid99Hdr,1,sizeof (geoid99Hdr),fstr);
	if (readCount != sizeof (geoid99Hdr))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	if (CS_ferror (fstr))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}

	/* Determine the size of the file. */
	if (CS_fseek (fstr,0L,SEEK_END))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}
	__This->fileSize = CS_ftell (fstr);
	if (__This->fileSize < 0L)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}

	/* This constructor doesn't need the file any more. */
	CS_fclose (fstr);
	fstr = NULL;

	/* Swap the bytes if necessary.  In all the data files I've seen, iKind is 32
	   bit 1.  If it is a one in the structure, than the file is in the same byte
	   order as the machine we are running on, and swapping is unnecessary.  If
	   iKind is not a one, we assume that is because of byte order, and we do a
	   swap.  Note, however, that we preserve iKind as it was before swapping so
	   that we know whether to swap or not in the other functions in this code
	   module. */

	__This->iKind = geoid99Hdr.iKind;
	if (geoid99Hdr.iKind != 1L)
	{
		/* CSbswap is a variation on CS_bswap.  CSbswap always swaps. */
		CSbswap (&geoid99Hdr,cs_BSWP_Geoid99Hdr);
	}

	/* At this point, geoid99Hdr.iKind should be a one, or either the file
	   is corrupted, or we don't understand the file format properly. */

	if (geoid99Hdr.iKind != 1L)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Extract the important stuff from the header.  Note that the longitude in the header
	   is a zero thru 360 value, proceeding east from Greenwich.  This makes a lot of sense
	   since Alaska crosses the 190 degree crack.  However, it is inconsistent with
	   all the other stuff.  So, we do the following kludge, which is consistent with the
	   NADCON data files. */
	lngMin = geoid99Hdr.lngMin;
	lngMax = lngMin + (geoid99Hdr.lngDelta * (geoid99Hdr.lngCount - 1));
	if (lngMin >= 180.0 || lngMax > 180.0)
	{
		__This->coverage.southWest [LNG] = geoid99Hdr.lngMin - cs_K360;
	}
	else
	{
		__This->coverage.southWest [LNG] = geoid99Hdr.lngMin;
	}
	__This->coverage.southWest [LAT] = geoid99Hdr.latMin;
	__This->deltaLng = geoid99Hdr.lngDelta;
	__This->deltaLat = geoid99Hdr.latDelta;
	__This->coverage.northEast [LNG] = __This->coverage.southWest [LNG] + (geoid99Hdr.lngDelta * (geoid99Hdr.lngCount - 1));
	__This->coverage.northEast [LAT] = __This->coverage.southWest [LAT] + (geoid99Hdr.latDelta * (geoid99Hdr.latCount - 1));
	__This->coverage.density = (__This->deltaLng < __This->deltaLat) ? __This->deltaLng : __This->deltaLat;
	if (density != 0.0) __This->coverage.density = density;
	__This->elementCount = geoid99Hdr.lngCount;
	__This->recordCount = geoid99Hdr.latCount;
	__This->recordSize = geoid99Hdr.lngCount * (int)sizeof (float);

	/* Verify the integrity of the file. */
	lngTmp = __This->recordCount * __This->recordSize + sizeof (geoid99Hdr);
	if (lngTmp != __This->fileSize)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Now that we know recordSize, we can adjust the bufferSize for maximum
	   efficiency. */
	if (__This->bufferSize > __This->fileSize)
	{
		__This->bufferSize = __This->fileSize;
	}
	else
	{
		if (__This->bufferSize > (3 * __This->recordSize))
		{
			/* Maximum efficiency is obtained with a buffer size whch is
			   a multiple of the record size. */
			__This->bufferSize = (__This->bufferSize / __This->recordSize) * __This->recordSize;
		}
		else
		{
			/* We require a minimum buffer size of 3 records. */
			__This->bufferSize = 3 * __This->recordSize;
		}
	}

	return (__This);
error:
	CSdeleteGeoid99GridFile (__This);
	return NULL;
}
Beispiel #4
0
/*****************************************************************************
	This function would be a private function in C++.
	This function sets the currentCell member to the cell which covers the
	provided geographic coordinate.  Returns 0 on success or a negative value
	for a system error of some sort (i.e. file I/O).  Per the design of this
	object, this function is not to be called unless the provided source
	coordinate is within the coverage of the object.
*/
int CScalcGeoid99GridFile (struct csGeoid99GridFile_* __This,double* result,Const double* sourceLL)
{
	extern double cs_One;

	int eleNbr;
	int recNbr;
	int readCount;
	int checkCount;

	long lngTmp;
	long checkSeek;
	long fpos;
	long fposBegin;
	long fposEnd;
	long swapCount;

	char* chrPtr;
	float* fltPtr;

	double centerLL [2];
	double deltaLL [2];
	
	char swapSpec [16];

	/* Float array carries the 3x3 array as follows:
		         North

		W       6  7  8      E
		e       3  4  5      a
		s       0  1  2      s
		t                    t 
			     South          */
	float array [9];

	enum edgeEffects {	edgeNone = 0,
						edgeSouthwest,
						edgeSouth,
						edgeSoutheast,
						edgeEast,
						edgeNortheast,
						edgeNorth,
						edgeNorthwest,
						edgeWest
					 } edge;
	edge = edgeNone;

	/* We are not supposed to get here unless the sourceLL is within the coverage of the
	   file object.  We make sure of that now.  This makes life much easier below.  Use the
	   CStestGeoid99GridFile function to select the proper csGeoid99GridFile object. */
	if (sourceLL [LNG] < __This->coverage.southWest [LNG] || sourceLL [LNG] > __This->coverage.northEast [LNG] ||
	    sourceLL [LAT] < __This->coverage.southWest [LAT] || sourceLL [LAT] > __This->coverage.northEast [LAT])
	{
		CS_stncp (csErrnam,"CS_geoid99:1",MAXPATH);
		CS_erpt  (cs_ISER);
		goto error;
	}
	   
	/* Compute the basic indices to the cell in the data file.  We're supposed to come up
	   with a reference to the closest point.  Since we know the source coordinate is within
	   range, dealing with the edges is rather easy. */
	eleNbr = (long)(((sourceLL [LNG] - __This->coverage.southWest [LNG]) / __This->deltaLng) + 0.5);
	recNbr = (long)(((sourceLL [LAT] - __This->coverage.southWest [LAT]) / __This->deltaLat) + 0.5);

	/* Determine the if an edge effect applies. */
	if (recNbr < 1)
	{
		recNbr = 1;
		if (eleNbr < 1)
		{
			eleNbr = 1;
			edge = edgeSouthwest;
		}
		else if (eleNbr >= (__This->elementCount - 1))
		{
			eleNbr = __This->elementCount - 2;
			edge = edgeSoutheast;
		}
		else
		{
			edge = edgeSouth;
		}
	}
	else if (recNbr >= (__This->recordCount - 1))
	{
		if (eleNbr < 1)
		{
			eleNbr = 1;
			edge = edgeNorthwest;
		}
		else if (eleNbr >= (__This->elementCount - 1))
		{
			eleNbr = __This->elementCount - 2;
			edge = edgeNortheast;
		}
		else
		{
			edge = edgeNorth;
		}
	}
	else
	{
		if (eleNbr < 1)
		{
			eleNbr = 1;
			edge = edgeWest;
		}
		else if (eleNbr > (__This->elementCount -1))
		{
			eleNbr = __This->elementCount - 2;
			edge = edgeEast;
		}
		else
		{
			edge = edgeNone;
		}
	}

	/* Compute the minimal region of the file which we need to read. */
	fposBegin = sizeof (struct csGeoid99Hdr_) + (recNbr - 1) * __This->recordSize;
	fposEnd = fposBegin + (__This->recordSize * 3);
	if (fposEnd > __This->fileSize) fposEnd = __This->fileSize;
	
	/* Do we have a buffer?  Could have been released.  Maybe this is the
	   first access. */
	if (__This->dataBuffer == NULL)
	{
		__This->dataBuffer = CS_malc ((size_t)__This->bufferSize);
		if (__This->dataBuffer == NULL)
		{
			CS_erpt (cs_NO_MEM);
			goto error;
		}

		/* Make sure the rest of this stuff knows the buffer is empty.  These values
		   will fail to match any specific file position. */
		__This->bufferBeginPosition = -1L;
		__This->bufferEndPosition = -2L;
	}

	/* See if the stuff we want is in the buffer.  Careful here, all of the intended
	   range must be in the buffer, not just a portion of it. */
	if (fposBegin < __This->bufferBeginPosition || fposBegin > __This->bufferEndPosition ||
		fposEnd   < __This->bufferBeginPosition || fposEnd   > __This->bufferEndPosition)
	{
		/* The data we need is not there; we need to read it in.  Is the file open? */
		if (__This->strm == NULL)
		{
			__This->strm = CS_fopen (__This->filePath,_STRM_BINRD);
			if (__This->strm == NULL)
			{
				CS_stncp (csErrnam,__This->filePath,MAXPATH);
				CS_erpt (cs_DTC_FILE);
				goto error;
			}
			/* We do our own buffering, turn stream buffering off. */
			setvbuf (__This->strm,NULL,_IONBF,0);
		}

		/* Compute the starting position of the actual read. */
		if (__This->bufferSize >= __This->fileSize)
		{
			__This->bufferBeginPosition = 0L;
			__This->bufferEndPosition = __This->fileSize;
			readCount = __This->fileSize;
		}
		else
		{
			/* We need to doa partial read, the normal case.  Initialize for the
			   minimal case computed above, then expand as is possible.  Note, we
			   get here only when a read has to be done. */
			__This->bufferBeginPosition = fposBegin;
			__This->bufferEndPosition = fposEnd;
			readCount = __This->bufferEndPosition - __This->bufferBeginPosition;

			/* In this section, lngTmp is the number of additional records
			   which can fit in the buffer. */
			lngTmp = (__This->bufferSize - readCount) / __This->recordSize;
			if (lngTmp > 3L)
			{
				/* Move the beginning of the read up by one half of the
				   amount of extra space in the buffer; but never past the
				   beginning of record number 1. */
				lngTmp = lngTmp / 2;
				__This->bufferBeginPosition -= __This->recordSize * lngTmp;
				if (__This->bufferBeginPosition < sizeof (struct csGeoid99Hdr_))	/*lint !e574 */
				{
					__This->bufferBeginPosition = sizeof (struct csGeoid99Hdr_);
				}
				readCount = __This->bufferEndPosition - __This->bufferBeginPosition;
			}

			lngTmp = (__This->bufferSize - readCount) / __This->recordSize;
			if (lngTmp > 3L)
			{
				/* Move the end of the read back by the amount of extra
				   space in the buffer, but never past the end of the file. */
				__This->bufferEndPosition += __This->recordSize * lngTmp;
				if (__This->bufferEndPosition > __This->fileSize)
				{
					__This->bufferEndPosition = __This->fileSize;
				}
				readCount = __This->bufferEndPosition - __This->bufferBeginPosition;
			}

			lngTmp = (__This->bufferSize - readCount) / __This->recordSize;
			if (lngTmp > 0L)
			{
				/* In case the expanded end of read exceeded the end of the
				   file, we can move the beginning of the read up some more,
				   However, never more than the beginning of the first
				   data record. */
				__This->bufferBeginPosition -= __This->recordSize * lngTmp;
				if (__This->bufferBeginPosition < sizeof (struct csGeoid99Hdr_))	/*lint !e574 */
				{
					__This->bufferBeginPosition = sizeof (struct csGeoid99Hdr_);
				}
				readCount = __This->bufferEndPosition - __This->bufferBeginPosition;
			}

			/* Defensive programming. */
			if (readCount != __This->bufferSize)
			{
				CS_stncp (csErrnam,"CS_geoid99:2",MAXPATH);
				CS_erpt (cs_ISER);
				goto error;
			}
		}

		/* OK, read in the data. */
		checkSeek = CS_fseek (__This->strm,__This->bufferBeginPosition,SEEK_SET);
		if (checkSeek < 0L)
		{
			CS_stncp (csErrnam,__This->filePath,MAXPATH);
			CS_erpt (cs_IOERR);
			goto error;
		}
		checkCount = (long)CS_fread (__This->dataBuffer,1,(size_t)readCount,__This->strm);
		if (checkCount != readCount)
		{
			CS_stncp (csErrnam,__This->filePath,MAXPATH);
			CS_erpt (cs_INV_FILE);
			goto error;
		}
		if (CS_ferror (__This->strm))
		{
			CS_stncp (csErrnam,__This->filePath,MAXPATH);
			CS_erpt (cs_IOERR);
			goto error;
		}

		/* Under certain circumstances, it will be rather inefficient to swap bytes here.
		   However, we swap here to preclude the chance of swapping the data twice, and
		   the chance that unswapped floats appear to be Nan's or something ugly like
		   that.  So, this may be somewhat inefficient, but it is the safest place
		   to put the swap.  In general, Geoid99 files are in little endian order, and
		   Geoid 2003 files are in Big endian order.  Thus, by using the appropriate
		   files, you may be able to skip the whole issue of byte swapping here
		   altogether. */

		if (__This->iKind != 1L)
		{
			/* Here if some swapping has to be done.  Need to exercise some care.
			   If the whole file was read in, we have a header on the front which
			   we don't want to swap.  Otherwise, we can treat the buffer as an
			   array of floats, which is rather simple.
			   
			   In the code below, we use lngTmp as the number of bytes on the
			   front of the buffer which we must omit from the swapping process. */

			lngTmp = (long)sizeof (struct csGeoid99Hdr_) - __This->bufferBeginPosition;
			if (lngTmp < 0) lngTmp = 0L;
			
			swapCount = (__This->bufferEndPosition - (__This->bufferBeginPosition + lngTmp)) / sizeof (float);
			sprintf (swapSpec,"%ldf",swapCount);
			chrPtr = (char *)(__This->dataBuffer) + lngTmp;
			CSbswap (chrPtr,swapSpec);
		}

		/* We have the desired data in the buffer.  If we read in the whole file,
		   we close the stream now.  No need to have the file descriptor open. */
		if (__This->bufferSize == __This->fileSize)
		{
			CS_fclose (__This->strm);
			__This->strm = NULL;
		}
	}

	/* Compute the delta into the grid cell we will contruct below.  Note, we are using adjusted
	   recNbr and eleNbr variables here. */
	centerLL [LNG] = __This->coverage.southWest [LNG] + __This->deltaLng * (double)eleNbr;
	centerLL [LAT] = __This->coverage.southWest [LAT] + __This->deltaLat * (double)recNbr;
	deltaLL [LNG] = ((sourceLL [LNG] - centerLL [LNG]) / __This->deltaLng) + cs_One;
	deltaLL [LAT] = ((sourceLL [LAT] - centerLL [LAT]) / __This->deltaLat) + cs_One;

	/* OK, the necessary stuff should be in the buffer.  We do what is necessary to
	   populate the array.  Notice, we populate the array in a way that the edge
	   effects come out correct using a standard algorithm below. */
	switch (edge) {
	case edgeNone:
		fpos = sizeof (struct csGeoid99Hdr_) + (recNbr * __This->recordSize) + (eleNbr * sizeof (float));

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr += __This->recordSize;
		fltPtr = (float *)(chrPtr);
		array [6] = *(fltPtr - 1);
		array [7] = *fltPtr;
		array [8] = *(fltPtr + 1);

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);
		array [3] = *(fltPtr - 1);
		array [4] = *fltPtr;
		array [5] = *(fltPtr + 1);

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr -= __This->recordSize;
		fltPtr = (float *)(chrPtr);
		array [0] = *(fltPtr - 1);
		array [1] = *fltPtr;
		array [2] = *(fltPtr + 1);
		break;

	case edgeSouthwest:
		fpos = sizeof (struct csGeoid99Hdr_);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [7] = array [8] = *fltPtr;
		array [3] = array [4] = array [5] = *fltPtr;
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = deltaLL [LAT] = cs_One;
		break;

	case edgeSouth:
		fpos = sizeof (struct csGeoid99Hdr_) + eleNbr * sizeof (float);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [3] = array [0] = *(fltPtr - 1);
		array [7] = array [4] = array [1] = *fltPtr;
		array [8] = array [5] = array [2] = *(fltPtr + 1);

		deltaLL [LAT] = cs_One;
		break;

	case edgeSoutheast:
		fpos = sizeof (struct csGeoid99Hdr_) + (__This->elementCount - 1) * sizeof (float);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [7] = array [8] = *fltPtr;
		array [3] = array [4] = array [5] = *fltPtr;
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = deltaLL [LAT] = cs_One;
		break;

	case edgeEast:
		fpos = sizeof (struct csGeoid99Hdr_) + recNbr * __This->recordSize + (__This->elementCount - 1) * sizeof (float);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr += __This->recordSize;
		fltPtr = (float *)(chrPtr);

		array [6] = array [7] = array [8] = *fltPtr;

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);
		array [3] = array [4] = array [5] = *fltPtr;

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr -= __This->recordSize;
		fltPtr = (float *)(chrPtr);
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = cs_One;
		break;

	case edgeNortheast:
		fpos = sizeof (struct csGeoid99Hdr_) + (__This->recordCount - 1) * __This->recordSize + (__This->elementCount - 1) * sizeof (float);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [7] = array [8] = *fltPtr;
		array [3] = array [4] = array [5] = *fltPtr;
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = deltaLL [LAT] = cs_One;
		break;

	case edgeNorth:
		fpos = sizeof (struct csGeoid99Hdr_) + (__This->recordCount - 1) * __This->recordSize + eleNbr * sizeof (float);
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [3] = array [0] = *(fltPtr - 1);
		array [7] = array [4] = array [1] = *fltPtr;
		array [8] = array [5] = array [2] = *(fltPtr + 1);

		deltaLL [LAT] = cs_One;
		break;

	case edgeNorthwest:
		fpos = sizeof (struct csGeoid99Hdr_) + (__This->recordCount - 1) * __This->recordSize;
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);

		array [6] = array [7] = array [8] = *fltPtr;
		array [3] = array [4] = array [5] = *fltPtr;
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = deltaLL [LAT] = cs_One;
		break;

	case edgeWest:
		fpos = sizeof (struct csGeoid99Hdr_) + recNbr * __This->recordSize;
		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr += __This->recordSize;
		fltPtr = (float *)(chrPtr);
		array [6] = array [7] = array [8] = *fltPtr;

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		fltPtr = (float *)(chrPtr);
		array [3] = array [4] = array [5] = *fltPtr;

		chrPtr = (char *)(__This->dataBuffer) + (fpos - __This->bufferBeginPosition);
		chrPtr -= __This->recordSize;
		fltPtr = (float *)(chrPtr);
		array [0] = array [1] = array [2] = *fltPtr;

		deltaLL [LNG] = cs_One;
		break;
	}

	/* Do the calculations. */
	*result = CSgeoidQterp (deltaLL,array);
	return 0;

error:
	/* Release the resources allocated to this object.  The next call to this
	   object would then require a refresh. */
	CSreleaseGeoid99GridFile (__This);

	/* Negative return indicates a system error of sorts. */
	return -1;
}
Beispiel #5
0
/*****************************************************************************
	Constructor
*/
struct csGeoid96GridFile_* CSnewGeoid96GridFile (Const char *path,long32_t bufferSize,ulong32_t flags,double density)
{
	extern char cs_DirsepC;
	extern char cs_ExtsepC;
	extern char csErrnam [];

	size_t readCount;
	long lngTmp;
	char *cp1, *cp2;
	csFILE *fstr;
	struct csGeoid96GridFile_* __This;
	char cTemp [MAXPATH];
	struct csNadconFileHdr_ nadconHdr;

	/* Prepare for an error. */
	__This = NULL;
	fstr = NULL;

	/* Malloc and initialize */
	__This = CS_malc (sizeof (struct csGeoid96GridFile_));
	if (__This == NULL)
	{
		CS_erpt (cs_NO_MEM);
		goto error;
	}
	CSinitGeoid96 (__This);

	/* Set default values for all members. */
	__This->bufferSize = bufferSize;
	if (__This->bufferSize < 0) __This->bufferSize = 0;

	/* Save file path/name. */
	CS_stncp (__This->filePath,path,sizeof (__This->filePath));
	CS_stncp (cTemp,path,sizeof (cTemp));

	/* Set up the type of file.  Get cp1 to point at the file
	   name, and cp2 to point at the extension.  We consider it
	   an error if we are not given a full path name.  Note,
	   we care not about the format of the drive specification.
	   But there must be at least one directory and there must
	   be an extension. */
	cp1 = strrchr (cTemp,cs_DirsepC);
	if (cp1 == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	cp1 += 1;
	cp2 = strchr (cp1,cs_ExtsepC);
	if (cp2 == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	*cp2++ = '\0';
	CS_stncp (__This->fileName,cp1,sizeof (__This->fileName));

	/* The thing should have a .geo extension to be processed by us. */
	if (CS_stricmp (cp2,"geo"))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Get the file information header. */
	fstr = CS_fopen (__This->filePath,_STRM_BINRD);
	if (fstr == NULL)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_DTC_FILE);
		goto error;
	}
	readCount = CS_fread (&nadconHdr,1,sizeof (nadconHdr),fstr);
	if (readCount != sizeof (nadconHdr))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}
	if (CS_ferror (fstr))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}

	/* Determine the size of the file. */
	if (CS_fseek (fstr,0L,SEEK_END))
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}
	__This->fileSize = CS_ftell (fstr);
	if (__This->fileSize < 0L)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_IOERR);
		goto error;
	}

	/* This constructor doesn't need the file any more. */
	CS_fclose (fstr);
	fstr = NULL;

	/* Swap the bytes if necessary. */
	CS_bswap (&nadconHdr,cs_BSWP_NadconFileHdr);

	/* The extra stuff here is required as conversions of floats to doubles
	   does not always provide precise results.  To get the precise results we
	   require, we assume that the value (which is in degrees) is an intergal
	   number of seconds. */
	lngTmp = (long)(((double)nadconHdr.del_lng * 3600.0) + 0.4);
	__This->deltaLng = ((double)lngTmp / 3600.0);
	lngTmp = (long)(((double)nadconHdr.del_lat * 3600.0) + 0.4);
	__This->deltaLat = ((double)lngTmp / 3600.0);

	/* Now we can do the rest of this stuff. */
	__This->coverage.southWest [LNG] = nadconHdr.min_lng;
	__This->coverage.southWest [LAT] = nadconHdr.min_lat;
	__This->coverage.northEast [LNG] = nadconHdr.min_lng + (__This->deltaLng * (nadconHdr.ele_cnt - 1));
	__This->coverage.northEast [LAT] = nadconHdr.min_lat + (__This->deltaLat * (nadconHdr.rec_cnt - 1));
	__This->coverage.density = (__This->deltaLng < __This->deltaLat) ? __This->deltaLng : __This->deltaLat;
	if (density != 0.0) __This->coverage.density = density;
	__This->elementCount = nadconHdr.ele_cnt;
	__This->recordCount = nadconHdr.rec_cnt;
	__This->recordSize = nadconHdr.ele_cnt * (int)sizeof (float) + (int)sizeof (long);

	/* Verify the integrity of the file. */
	lngTmp = (__This->recordCount + 1) * __This->recordSize;
	if (lngTmp != __This->fileSize)
	{
		CS_stncp (csErrnam,__This->filePath,MAXPATH);
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Now that we know recordSize, we can adjust the bufferSize for maximum
	   efficiency. */
	if (__This->bufferSize > __This->fileSize)
	{
		__This->bufferSize = __This->fileSize;
	}
	else
	{
		if (__This->bufferSize > (3 * __This->recordSize))
		{
			/* Maximum efficiency is obtained with a buffer size whch is
			   a multiple of the record size. */
			__This->bufferSize = (__This->bufferSize / __This->recordSize) * __This->recordSize;
		}
		else
		{
			/* We require a minimum buffer size of 3 records. */
			__This->bufferSize = 3 * __This->recordSize;
		}
	}

	return (__This);
error:
	CSdeleteGeoid96GridFile (__This);
	return NULL;
}
Beispiel #6
0
/* Interpolation Calculator
	The comment below is stale now that we store the entire grid file in memory,
	but is interesting nonetheless as it documents unusual properties of NTv2
	grids.

	====

	Due to a bust in the file format, we do not buffer up grid cells and stuff.
	There are a couple of sub-grids which overlap other grids in such a way that
	buffering can cause errors.  So, at least until (if ever) the data file is
	corrected, we do no buffering of the grid cells.

	Also, this file format is being adopted by others, such as the Australians.
	We don't know what they are going to do.  So to be safe, NO BUFFERING OF
	GRID CELLS.

	Also, due to the sub-grid nature of the data file, we do not buffer the
	data file in any special way; we simply use normal stream buffering.  We
	do, however, use a normal stream buffer of the size specified in the
	main object.
*/
int CScalcNTv2 (struct cs_NTv2_* thisPtr,double deltaLL [2],Const double source [2])
{
	extern double cs_Zero;				/* 0.0 */
	extern double cs_LlNoise;			/* 1.0E-12 */
	extern char csErrnam [MAXPATH];

	short onLimit;
	unsigned short eleNbr, rowNbr;

	int rtnValue;
	int swapping;

	csFILE* stream = NULL;
	size_t readCnt;
	long32_t filePosition;
	struct csNTv2SubGrid_ *cvtPtr;

	double wpLL [2];
	double seCell [2];
	double nwCell [2];

	struct TcsCaNTv2Data southEast;
	struct TcsCaNTv2Data southWest;
	struct TcsCaNTv2Data northEast;
	struct TcsCaNTv2Data northWest;

	/* Until we know differently. */
	rtnValue = csGRIDI_ST_SYSTEM;
	thisPtr->CellIsValid = FALSE;

	/* In case of an error.  This saves duplication of this many many times. */
	CS_stncp (csErrnam,thisPtr->FilePath,MAXPATH);

	/* Remember, source is East Positive.  All NTv2 files are West Positive. */

	/* Locate the appropriate sub-grid.  If there is none, than there is no
	   coverage.  There are two algorithms:  the original one and one invented
	   to cater to the Spaniards (and maybe some others in the future).
	   
	   In the original algorithm, we search through the top level of parent
	   grids looking for coverage.  The top level parents are those which have
	   no parent.  If none is found, there is no coverage.  If we locate a parent
	   which provides coverage, we examine all children of that parent looking
	   for a sub-grid; and so on.
	   
	   In the Spanish algorithm, we search all grids, and choose the grid which
	   produces the smallest cell size.  This is necessary as the grids are
	   allowed to overlap in the Spanish variation. */
	cvtPtr = CSlocateSubNTv2 (thisPtr,source);
	
	/* OK, if cvtPtr is not NULL, its a pointer to the appropriate sub grid
	   for this conversion. */
	if (cvtPtr != NULL)
	{
		/* NTv2 files consider west longitude to be positive. */
		wpLL [LNG] = -source [LNG];
		wpLL [LAT] =  source [LAT];

		/* Determine the status of onLimit.  This indicates if the point to be
		   converted actually resides on the northern or western edge of the
		   grid cell. */
		onLimit = 0;
		if (fabs (wpLL [LAT] - cvtPtr->NwReference [LAT]) <= cs_LlNoise) onLimit |= 1;
		if (fabs (wpLL [LNG] - cvtPtr->NwReference [LNG]) <= cs_LlNoise) onLimit |= 2;

		if (thisPtr->fileImage == NULL)
		{
			stream = CS_fopen (thisPtr->FilePath,_STRM_BINRD);
			if (stream == NULL)
			{
				CS_stncp (csErrnam,thisPtr->FilePath,MAXPATH);
				CS_erpt (cs_DTC_FILE);
				goto error;
			}
			setvbuf (stream,NULL,_IOFBF,(size_t)thisPtr->BufferSize);

			// Determine the size of the file.
			if (CS_fseek (stream,0L,SEEK_END))
			{
				CS_stncp (csErrnam,thisPtr->FilePath,MAXPATH);
				CS_erpt (cs_IOERR);
				goto error;
			}
			thisPtr->fileImageSize = CS_ftell (stream);
			if (thisPtr->fileImageSize < 0L)
			{
				CS_stncp (csErrnam,thisPtr->FilePath,MAXPATH);
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (CS_fseek (stream, 0L, SEEK_SET))
			{
				CS_stncp (csErrnam,thisPtr->FilePath,MAXPATH);
				CS_erpt (cs_IOERR);
				goto error;
			}

			// Prepare memory
			thisPtr->fileImage = (char*)CS_malc(thisPtr->fileImageSize);
			if (thisPtr->fileImage == NULL)
			{
				CS_erpt (cs_NO_MEM);
				goto error;
			}

			// Copy everything into the memory
			readCnt = CS_fread(thisPtr->fileImage,
				1,
				thisPtr->fileImageSize,
				stream);
			if (CS_ferror(stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}

			CS_fclose (stream); stream = NULL;
		}

		/* Compute onLimit for this point and the selected sub-grid regardless
		   of how we got here.  This should now only occur at the extreme edges
		   of the entire file coverage. */
		onLimit = 0;
		if (fabs (wpLL [LAT] - cvtPtr->NwReference [LAT]) <= cs_LlNoise) onLimit |= 1;
		if (fabs (wpLL [LNG] - cvtPtr->NwReference [LNG]) <= cs_LlNoise) onLimit |= 2;

		/* Compute the elements required for the file access.  This is common to
		   all cases of "onLimit". */
		eleNbr = (unsigned short)(((wpLL [LNG] - cvtPtr->SeReference [LNG]) / cvtPtr->DeltaLng) + cs_LlNoise);
		rowNbr = (unsigned short)(((wpLL [LAT] - cvtPtr->SeReference [LAT]) / cvtPtr->DeltaLat) + cs_LlNoise);

		/* Compute the boundaries of the specific cell we dealing with, assuming
		   onLimit is zero (which is the case 99.999% of the time). */
		seCell [LNG] = cvtPtr->SeReference [LNG] + cvtPtr->DeltaLng * (double)eleNbr;
		seCell [LAT] = cvtPtr->SeReference [LAT] + cvtPtr->DeltaLat * (double)rowNbr;
		nwCell [LNG] = seCell [LNG] + cvtPtr->DeltaLng;
		nwCell [LAT] = seCell [LAT] + cvtPtr->DeltaLng;

		/* Build the extent portions of the grid cells. */
		thisPtr->longitudeCell.seCorner [LNG] = seCell [LNG];
		thisPtr->longitudeCell.seCorner [LAT] = seCell [LAT];
		thisPtr->longitudeCell.nwCorner [LNG] = nwCell [LNG];
		thisPtr->longitudeCell.nwCorner [LAT] = nwCell [LAT];
		thisPtr->longitudeCell.deltaLng = cvtPtr->DeltaLng;
		thisPtr->longitudeCell.deltaLat = cvtPtr->DeltaLat;
		thisPtr->longitudeCell.density = cvtPtr->Density;

		thisPtr->latitudeCell.seCorner [LNG] = seCell [LNG];
		thisPtr->latitudeCell.seCorner [LAT] = seCell [LAT];
		thisPtr->latitudeCell.nwCorner [LNG] = nwCell [LNG];
		thisPtr->latitudeCell.nwCorner [LAT] = nwCell [LAT];
		thisPtr->latitudeCell.deltaLng = cvtPtr->DeltaLng;
		thisPtr->latitudeCell.deltaLat = cvtPtr->DeltaLat;
		thisPtr->latitudeCell.density = cvtPtr->Density;

		/* We could reduce the code complexity here by getting smart with the
		   onLimit thing.  However, this gets very tricky.  My excuse here is
		   that what is code below emulates the way the Canadians did it in
		   FORTRAN as best we can do in C. */
		if (onLimit == 0)
		{
			/* The normal case, probably about 99.9999 percent of the time.
			   Read the data into my record buffer. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * thisPtr->RecSize;

			if ((filePosition + sizeof(southEast) + sizeof(southWest)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&southEast, thisPtr->fileImage + filePosition, sizeof(southEast));
			/* Read southwest shifts. */
			memcpy(&southWest,
				   thisPtr->fileImage + filePosition + sizeof(southEast),
				   sizeof(southWest));

			/* Read northeast shifts. */
			filePosition += cvtPtr->RowSize;

			if ((filePosition + sizeof(northEast) + sizeof(northWest)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&northEast, thisPtr->fileImage + filePosition, sizeof(northEast));

			/* Read northwest shifts. */
			memcpy(&northWest,
				   thisPtr->fileImage + filePosition + sizeof(northEast),
				   sizeof(northWest));

			/* Swap as necessary. */
			swapping = CS_bswap (&southEast,cs_BSWP_NTv2Data);
			if (swapping)
			{
				CS_bswap (&southWest,cs_BSWP_NTv2Data);
				CS_bswap (&northEast,cs_BSWP_NTv2Data);
				CS_bswap (&northWest,cs_BSWP_NTv2Data);
			}

			/* Build the grid cell AA, BB, CC, and DD values. */
			thisPtr->longitudeCell.currentAA = southEast.del_lng;
			thisPtr->longitudeCell.currentBB = southWest.del_lng - southEast.del_lng;
			thisPtr->longitudeCell.currentCC = northEast.del_lng - southEast.del_lng;
			thisPtr->longitudeCell.currentDD = northWest.del_lng - southWest.del_lng - northEast.del_lng + southEast.del_lng;

			thisPtr->latitudeCell.currentAA = southEast.del_lat;
			thisPtr->latitudeCell.currentBB = southWest.del_lat - southEast.del_lat;
			thisPtr->latitudeCell.currentCC = northEast.del_lat - southEast.del_lat;
			thisPtr->latitudeCell.currentDD = northWest.del_lat - southWest.del_lat - northEast.del_lat + southEast.del_lat;
		}
		else if (onLimit == 1)
		{
			/* Point is on the extreme northern edge of the sub-grid.  This occurs
			   ocassionally.  In this case, the "northern" boundary of the grid cell
			   doesn't exist, and we must manufacture such.  This is called a
			   virtual cell in the Canadian documentation.  */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * thisPtr->RecSize;

			if ((filePosition + sizeof(southEast) + sizeof(southWest)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&southEast, thisPtr->fileImage + filePosition, sizeof(southEast));
			/* Read southwest shifts. */
			memcpy(&southWest,
				   thisPtr->fileImage + filePosition + sizeof(southEast),
				   sizeof(southWest));

			/* Swap as necessary. */
			swapping = CS_bswap (&southEast,cs_BSWP_NTv2Data);
			if (swapping)
			{
				CS_bswap (&southWest,cs_BSWP_NTv2Data);
			}

			/* Do not attempt to read the northern boundary, it ain't there.
			   Compute the AA, BB, CC, DD values. */
			thisPtr->longitudeCell.currentAA = southEast.del_lng;
			thisPtr->longitudeCell.currentBB = southWest.del_lng - southEast.del_lng;
			thisPtr->longitudeCell.currentCC = cs_Zero;
			thisPtr->longitudeCell.currentDD = cs_Zero;

			thisPtr->latitudeCell.currentAA = southEast.del_lat;
			thisPtr->latitudeCell.currentBB = southWest.del_lat - southEast.del_lat;
			thisPtr->latitudeCell.currentCC = cs_Zero;
			thisPtr->latitudeCell.currentDD = cs_Zero;
			
			/* Adjust the grid cell boundaries to indicate that the northern
			   limits are the same as the southern limits.  I.e. a grid cell
			   that has zero height. */
			thisPtr->longitudeCell.nwCorner [LAT] = thisPtr->longitudeCell.seCorner [LAT] + cs_LlNoise;
			thisPtr->latitudeCell.nwCorner [LAT]  = thisPtr->latitudeCell.seCorner [LAT] + cs_LlNoise;
		}
		else if (onLimit == 2)
		{
			/* Point is on the extreme western edge of the sub-grid. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * thisPtr->RecSize;

			if ((filePosition + sizeof(southEast)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&southEast, thisPtr->fileImage + filePosition, sizeof(southEast));

			/* Don't read the south west, it ain't there. */

			filePosition += cvtPtr->RowSize;

			if ((filePosition + sizeof(northEast)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&northEast, thisPtr->fileImage + filePosition, sizeof(northEast));
			
			/* Don't read the northwest, it ain't there. */
			swapping = CS_bswap (&southEast,cs_BSWP_NTv2Data);
			if (swapping)
			{
				CS_bswap (&northEast,cs_BSWP_NTv2Data);
			}

			thisPtr->longitudeCell.currentAA = southEast.del_lng;
			thisPtr->longitudeCell.currentBB = cs_Zero;
			thisPtr->longitudeCell.currentCC = northEast.del_lng - southEast.del_lng;
			thisPtr->longitudeCell.currentDD = cs_Zero;

			thisPtr->latitudeCell.currentAA = southEast.del_lat;
			thisPtr->latitudeCell.currentBB = cs_Zero;
			thisPtr->latitudeCell.currentCC = northEast.del_lat - southEast.del_lat;
			thisPtr->latitudeCell.currentDD = cs_Zero;

			/* Adjust the grid cell boundaries to indicate that the eastern
			   limits are the same as the western limits.  I.e. a grid cell
			   that has zero width. */
			thisPtr->longitudeCell.nwCorner [LNG] = thisPtr->longitudeCell.seCorner [LNG] + cs_LlNoise;
			thisPtr->latitudeCell.nwCorner [LNG]  = thisPtr->latitudeCell.seCorner [LNG] + cs_LlNoise;
		}
		else  /* onLimit == 3 */
		{
			/* Point is actually the northwestern corner of the sub-grid. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * thisPtr->RecSize;

			if ((filePosition + sizeof(southEast)) > thisPtr->fileImageSize)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			memcpy(&southEast, thisPtr->fileImage + filePosition, sizeof(southEast));

			/* Don't read anything else.  There's nothing there. */
			CS_bswap (&southEast,cs_BSWP_NTv2Data);

			/* Compute the AA, BB, CC, DD values. */
			thisPtr->longitudeCell.currentAA = southEast.del_lng;
			thisPtr->longitudeCell.currentBB = cs_Zero;
			thisPtr->longitudeCell.currentCC = cs_Zero;
			thisPtr->longitudeCell.currentDD = cs_Zero;

			thisPtr->latitudeCell.currentAA = southEast.del_lat;
			thisPtr->latitudeCell.currentBB = cs_Zero;
			thisPtr->latitudeCell.currentCC = cs_Zero;
			thisPtr->latitudeCell.currentDD = cs_Zero;

			/* Adjust the grid cell boundaries to indicate that the northeastern
			   limits are the same as the southwestern limits.  I.e. a grid cell
			   that has zero width and zero height. */
			thisPtr->longitudeCell.nwCorner [LNG] = thisPtr->longitudeCell.seCorner [LNG] + cs_LlNoise;
			thisPtr->latitudeCell.nwCorner [LNG]  = thisPtr->latitudeCell.seCorner [LNG] + cs_LlNoise;
			thisPtr->longitudeCell.nwCorner [LAT] = thisPtr->longitudeCell.seCorner [LAT] + cs_LlNoise;
			thisPtr->latitudeCell.nwCorner [LAT]  = thisPtr->latitudeCell.seCorner [LAT] + cs_LlNoise;
		}

		/* The cells are now valid, maybe.  We now work around a bust in the
		   Canadian NTV2_0.gsb grid data file. */
		thisPtr->CellIsValid = TRUE;

		/* Perform the interpolation calculation. */
		deltaLL [LNG] = CScalcNTv2GridCell (&thisPtr->longitudeCell,source);
		deltaLL [LAT] = CScalcNTv2GridCell (&thisPtr->latitudeCell,source);
		rtnValue = csGRIDI_ST_OK;
	}
	else
	{
		/* We didn't find a sub-grid.  The return value is +1 to indicate no
		   coverage. */
		deltaLL [LNG] = cs_Zero;
		deltaLL [LAT] = cs_Zero;
		rtnValue = csGRIDI_ST_COVERAGE;
	}
	csErrnam [0] = '\0';
	return rtnValue;
error:
	if (stream != NULL)
	{
		CS_fclose (stream); stream = NULL;
	}
	return csGRIDI_ST_SYSTEM;
}
Beispiel #7
0
int CStestS (int verbose)
{
	extern char cs_Dir [];
	extern char *cs_DirP;
	extern char cs_Csname [];
	extern union cs_Bswap_ cs_BswapU;

	int st = 0;
#ifdef __SKIP__
	size_t rdCnt;

	csFILE *strm;

	char magic [sizeof (cs_magic_t)];
	
	printf ("Switching byte order in all files for subsequent tests.\n");

	/* Now we force CS_swap into swap mode. */
	cs_BswapU.llll = 0x010203L;

	st = 0;	
#if _RUN_TIME < _rt_UNIXPCC
	/* It appears that there are problems with the directory tree scan stuff
	   under UNIX.  So, we simply comment this out for now. */
	/* Swap all the files. */
	if (verbose)
	{
		st = CS_swpal (CStestSa);
	}
	else
	{
		st = CS_swpal (NULL);
	}
#endif
	
	/* Now we set CS_bswap to operate correctly with the results;
	   regardless of what type of machine we are on. In order to do
	   this, we determine the current state of the binary files.
	   This may be the same as before if CS_swpal had some sort of
	   problem. */
	(void)strcpy (cs_DirP,cs_Csname);
	strm = CS_fopen (cs_Dir,_STRM_BINRD);
	if (strm == NULL)
	{
		st = cs_CSDICT;
	}
	else
	{
		rdCnt = CS_fread (&magic,1,sizeof (magic),strm);
		CS_fclose (strm);
		if (rdCnt != sizeof (magic))
		{
			st = CS_ferror (strm) ? cs_IOERR : cs_INV_FILE;
		}
		else
		{
			if (magic [0] != '\200')
			{
				/* Little endian order. */
				cs_BswapU.cccc [0] = 0x00;
				cs_BswapU.cccc [1] = 0x01;
				cs_BswapU.cccc [2] = 0x02;
				cs_BswapU.cccc [3] = 0x03;
			}
			else
			{
				/* Little endian order. */
				cs_BswapU.cccc [0] = 0x03;
				cs_BswapU.cccc [1] = 0x02;
				cs_BswapU.cccc [2] = 0x01;
				cs_BswapU.cccc [3] = 0x00;
			}
		}
	}
#endif
	return (st);
}
Beispiel #8
0
int CSinitNTv2 (struct cs_NTv2_* thisPtr,Const char *filePath,long32_t bufferSize,
															  ulong32_t flags,
															  double density)
{
	extern double cs_Sec2Deg;
	extern char cs_DirsepC;
	extern char csErrnam [];

	short idx;
	short parIdx;

	int overlap;
	int seekStat;

	size_t readCnt;
	size_t readCntRq;
	size_t malcCnt;
	long32_t skipAmount;

	char *cp;
	struct csNTv2SubGrid_* subPtr;
	struct csNTv2SubGrid_* kidPtr;
	struct csNTv2SubGrid_* parPtr;

	union csNtv2Hdrs_ fileHdr;
	struct csNTv2SubHdr_ fileSubHdr;

	char ctemp [MAXPATH];

	csFILE* stream = NULL;

	/* Try to prevent a likely crash. */
	if (thisPtr == NULL)
	{
		CS_stncp (csErrnam,"CS_ntv2::1",MAXPATH);
		CS_erpt (cs_ISER);
		return -1;
	}

	/* In the event of an error; this eliminates duplicating this many many
	   times. */
	CS_stncp (csErrnam,filePath,MAXPATH);

	/* Initialize the structure to harmless values. */
	thisPtr->SubGridDir = NULL;
	thisPtr->fileImage = NULL;
	thisPtr->fileImageSize = 0;
	thisPtr->HdrRecCnt = 0;
	thisPtr->SubCount = 0;
	thisPtr->RecSize = 16;
	thisPtr->CellIsValid = FALSE;
	thisPtr->SubOverlap = (short)((flags & 0x01) != 0);
	thisPtr->IntType = csNTv2TypeNone;
	thisPtr->BufferSize = bufferSize;
	thisPtr->sourceId [0] = '\0';
	if (thisPtr->BufferSize <= 0) thisPtr->BufferSize = csNTv2BufrSz;
	if (thisPtr->BufferSize <= 4096) thisPtr->BufferSize = 4096;
	CSinitNTv2GridCell (&thisPtr->longitudeCell);
	CSinitNTv2GridCell (&thisPtr->latitudeCell);

	/* Deal with the file path. */
	CS_stncp (thisPtr->FilePath,filePath,sizeof (thisPtr->FilePath));

	/* Extract and save last 15 characters of the data file name. */
	cp = strrchr (thisPtr->FilePath,cs_DirsepC);
	if (cp == NULL) cp = thisPtr->FilePath;
	CS_stncp (ctemp,cp,sizeof (ctemp));
	cp = strrchr (ctemp,'.');
	if (cp != NULL) *cp = '\0';
	cp = ctemp;
	if (strlen (ctemp) > 15)
	{
		cp = ctemp + strlen (ctemp) - 15;
	}
	CS_stncp (thisPtr->FileName,cp,sizeof (thisPtr->FileName));

	/* Open the file. */
	stream = CS_fopen (thisPtr->FilePath,_STRM_BINRD);
	if (stream == NULL)
	{
		CS_erpt (cs_DTC_FILE);
		goto error;
	}
	setvbuf (stream,NULL,_IOFBF,(size_t)thisPtr->BufferSize);

	/* We've got a file.  Read the header. */
	readCnt = CS_fread (&fileHdr,1,sizeof (fileHdr),stream);
	if (CS_ferror (stream))
	{
		CS_erpt (cs_IOERR);
		goto error;
	}
	if (readCnt != sizeof (fileHdr))
	{
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Verify that this is the kind of file we know how to deal with. */
	if (strncmp (fileHdr.Canadian.titl01,"NUM_OREC",8))
	{
		/* Opps!!! Not a CaNTv2 file. */
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Determine the type/source of the file. */
	if (fileHdr.Canadian.titl02 [0] == 'N' &&
	    fileHdr.Canadian.titl02 [1] == 'U')
	{
		/* It appears that the file is Canadian. */
		thisPtr->IntType = csNTv2TypeCanada;
		skipAmount = sizeof (struct csNTv2HdrCa_);
		CS_bswap (&fileHdr.Canadian,cs_BSWP_NTv2HdrCa);
	}
	else if (fileHdr.Australian.titl02 [0] == 'N' &&
			 fileHdr.Australian.titl02 [1] == 'U')
	{
		/* It appears to be an Australian file. */
		thisPtr->IntType = csNTv2TypeAustralia;
		skipAmount = sizeof (struct csNTv2HdrAu_);
		CS_bswap (&fileHdr.Australian,cs_BSWP_NTv2HdrAu);
	}
	else
	{
		/* Opps!!! Don't know what kind of file it is. */
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Reposition the input file as is appropriate due to the
	   type of file.  A little hoeky, but it should be portable. */
	seekStat = CS_fseek (stream,skipAmount,SEEK_SET);
	if (seekStat != 0)
	{
		CS_erpt (cs_INV_FILE);
		goto error;
	}

	/* Extract the valuable stuff. */
	if (thisPtr->IntType == csNTv2TypeCanada)
	{
		thisPtr->HdrRecCnt = fileHdr.Canadian.num_orec;
		thisPtr->SubCount = fileHdr.Canadian.num_file;
		thisPtr->SubHdrRecCnt = fileHdr.Canadian.num_srec;
	}
	else
	{
		thisPtr->HdrRecCnt = fileHdr.Australian.num_orec;
		thisPtr->SubCount = fileHdr.Australian.num_file;
		thisPtr->SubHdrRecCnt = fileHdr.Australian.num_srec;
	}
	/* The rest of the header is pretty much useless. */

	/* Now, we deal with the sub-directories.  THese are very
	   important. */
	malcCnt = sizeof (struct csNTv2SubHdr_) * (ulong32_t)thisPtr->SubCount;
	thisPtr->SubGridDir = (struct csNTv2SubGrid_ *)CS_malc (malcCnt);
	if (thisPtr->SubGridDir == NULL)
	{
		CS_erpt (cs_NO_MEM);
		goto error;
	}

	/* Initialize (i.e. construct) each of the sub-grid items we just
	   allocated. */
	for (idx = 0;idx < thisPtr->SubCount;idx += 1)
	{
		subPtr = &thisPtr->SubGridDir [idx];

		/* Initialize to a boundary which will not match anything. */
		subPtr->SouthWest [LNG] = 180.0;
		subPtr->SouthWest [LAT] = 90.0;
		subPtr->NorthEast [LNG] = -180.0;
		subPtr->NorthEast [LAT] = -90.0;

		/* Remember, these values as extracted from the file itself are
		   WEST positive. */
		subPtr->SeReference [LNG] =  180.0;
		subPtr->SeReference [LAT] =   90.0;
		subPtr->NwReference [LNG] = -180.0;
		subPtr->NwReference [LAT] =  -90.0;

		subPtr->DeltaLng  = 0.0;
		subPtr->DeltaLat  = 0.0;
		subPtr->Density   = 0.0;
		subPtr->FirstRecord = -1;
		subPtr->GridRecCnt = 0;
		subPtr->ParentIndex = -1;
		subPtr->ChildIndex = -1;
		subPtr->RowCount = 0;
		subPtr->ElementCount = 0;
		subPtr->RowSize = 0;
		subPtr->Cacheable = FALSE;
		subPtr->Name [0] = '\0';
		subPtr->Parent [0] = '\0';
	}

	/* Once for each sub-grid in the file; read in the header.  At this point,
	   we just read them in.  Later on, we peruse the array and figure out
	   who the mamas and the papas are. */
	for (idx = 0;idx < thisPtr->SubCount;idx += 1)
	{
		/* Kludge to handle the variation in format.  Doing this right
		   would require duplication of a whole bunch of code. So . . . */
		readCntRq = sizeof (fileSubHdr);
		if (thisPtr->IntType == csNTv2TypeAustralia) readCntRq -= 4;

		readCnt = CS_fread (&fileSubHdr,1,readCntRq,stream);
		if (CS_ferror (stream))
		{
			CS_erpt (cs_IOERR);
			goto error;
		}
		if (readCnt != readCntRq)
		{
			CS_erpt (cs_INV_FILE);
			goto error;
		}
		if (strncmp (fileSubHdr.titl01,"SUB_NAME",8))
		{
			CS_erpt (cs_INV_FILE);
			goto error;
		}
		if (thisPtr->IntType == csNTv2TypeCanada)
		{
			CS_bswap (&fileSubHdr,cs_BSWP_NTv2SubHdrCA);
		}
		else
		{
			CS_bswap (&fileSubHdr,cs_BSWP_NTv2SubHdrAU);
		}

		/* Collect the useful stuff. */		
		subPtr = &thisPtr->SubGridDir [idx];

		/* Data for each sub-grid immediately follows the sub-grid header. */
		subPtr->FirstRecord = CS_ftell (stream);

		/* These boundaries are rational east positive boundaries. */
		subPtr->SouthWest [LNG] = -fileSubHdr.w_long * cs_Sec2Deg;
		subPtr->SouthWest [LAT] =  fileSubHdr.s_lat  * cs_Sec2Deg;
		subPtr->NorthEast [LNG] = -fileSubHdr.e_long * cs_Sec2Deg;
		subPtr->NorthEast [LAT] =  fileSubHdr.n_lat  * cs_Sec2Deg;

		/* These boundaries are the screwy west positive ones used in the
		   NTv2 format. */
		subPtr->SeReference [LNG] = fileSubHdr.e_long * cs_Sec2Deg;
		subPtr->SeReference [LAT] = fileSubHdr.s_lat  * cs_Sec2Deg;
		subPtr->NwReference [LNG] = fileSubHdr.w_long * cs_Sec2Deg;
		subPtr->NwReference [LAT] = fileSubHdr.n_lat  * cs_Sec2Deg;

		/* The remainder of this is pretty rational. */
		subPtr->DeltaLng  = fileSubHdr.long_inc * cs_Sec2Deg;
		subPtr->DeltaLat  = fileSubHdr.lat_inc  * cs_Sec2Deg;

		/* We do not use Density in the calculations.  It is only used to
		   select one sub-grid over another in the case of overlap.  Yes,
		   I know.  The sub-grids at the same level are not suppoded to
		   overlap; but they do.  Call it job security for you an me. */
		subPtr->Density = (subPtr->DeltaLat < subPtr->DeltaLng) ? subPtr->DeltaLat : subPtr->DeltaLng;

		/* If the user has specified a default density value, we use it. */
		if (density != 0.0)
		{
			subPtr->Density = density;
		}

		/* Save the name for reporting purposes. */
		CS_stncp (subPtr->Name,fileSubHdr.sub_name,9);
		CS_stncp (subPtr->Parent,fileSubHdr.parent,9);

		subPtr->GridRecCnt = fileSubHdr.gs_count;
		/* WEST Positive, dummy.  The extra .01 is to eliminate possible fuzz
		   in the double portion of the calculations. */
		subPtr->RowCount = (unsigned short)(((subPtr->NwReference [LAT] - subPtr->SeReference [LAT]) / subPtr->DeltaLat) + 1.01);
		subPtr->ElementCount = (unsigned short)(((subPtr->NwReference [LNG] - subPtr->SeReference [LNG]) / subPtr->DeltaLng) + 1.01);
		subPtr->RowSize = (unsigned short)(subPtr->ElementCount * thisPtr->RecSize);

		/* Certain sub grids are not cacheable.  In the Canadian file, the region
		   which is not cacheable is rather small.  We use the csCaNTv2KludgeTable
		   to handle it.  The one Austrailian sub-grid we've seen is screwed up,
		   so we disable cacheing (at least for now), for all Australian files.
		   Australian, in this context, means file in the old Australian format,
		   not necessarily data files covering Australian geography.
		   
		   In the case of the Spanish variation, parent grids overlap, and
		   therefore none of the sub-grids are cacheable. */
//???? 	subPtr->Cacheable = (short)((thisPtr->IntType == csNTv2TypeCanada) && (thisPtr->SubOverlap == 0));
		subPtr->Cacheable = FALSE;

		/* Skip over the data records in the file. */
		skipAmount = subPtr->GridRecCnt * thisPtr->RecSize;
		seekStat = CS_fseek (stream,skipAmount,SEEK_CUR);
		if (seekStat != 0)
		{
			CS_erpt (cs_INV_FILE);
			goto error;
		}
	}

	/* Now we figure out who the mammas and the pappas are.  Note, all we have
	   to work with are parent names.  Therefore, we have to work bassackwards.

	   End result of all of this, is that each child needs to have the index
	   of its parent; and each sub-grid that has a child needs to be so marked. */
	for (idx =  0;idx < thisPtr->SubCount;idx += 1)
	{
		kidPtr = &thisPtr->SubGridDir [idx];
		if (CS_stricmp (kidPtr->Parent,"NONE    "))
		{
			/* Its a child, find the parent. */
			for (parIdx = 0;parIdx < thisPtr->SubCount;parIdx += 1)
			{
				parPtr = &thisPtr->SubGridDir [parIdx];
				if (!CS_stricmp (kidPtr->Parent,parPtr->Name))
				{
					/* Save the index of the parent. */
					kidPtr->ParentIndex = parIdx;

					/* Mark the parent as having a child, if not already so marked. */
					if (parPtr->ChildIndex == -1 || parPtr->ChildIndex > idx)
					{
						parPtr->ChildIndex = idx;
					}
				}
			}
		} 
	}

	/* To accomodate the Spanish (and perhaps others in the future, we check the
	   parent grids in the list of sub-grids for overlap.  If overlap exists,
	   we turn on the SubOverlap flag.  Of course, if this flag is already on,
	   we have nothing to do.  If we did indeed turn on the SubOverlap flag,
	   we need to cruise through all the sub-grids and set the Cacheable flag
	   to false to assure that no data from this file makes it to the grid cell
	   cache. */
	if (thisPtr->SubOverlap == 0)
	{
		for (parIdx = 0;parIdx < thisPtr->SubCount && thisPtr->SubOverlap == 0;parIdx += 1)
		{
			parPtr = &thisPtr->SubGridDir [parIdx];
			/* Top level grids only, we know the children overlap. */
			if (parPtr->ParentIndex >= 0) continue;

			overlap = FALSE;
			for (idx = 0;idx < thisPtr->SubCount;idx += 1)
			{
				if (idx == parIdx) continue;
				subPtr = &thisPtr->SubGridDir [idx];
				if (subPtr->ParentIndex >= 0) continue;
				
				/* See if subPtr overlaps with parPtr. */
				overlap  = subPtr->SeReference [LNG] > parPtr->SeReference [LNG] &&
						   subPtr->SeReference [LAT] > parPtr->SeReference [LAT] &&
						   subPtr->SeReference [LNG] < parPtr->NwReference [LNG] &&
						   subPtr->SeReference [LAT] < parPtr->NwReference [LAT];
				overlap |= subPtr->NwReference [LNG] > parPtr->SeReference [LNG] &&
						   subPtr->NwReference [LAT] > parPtr->SeReference [LAT] &&
						   subPtr->NwReference [LNG] < parPtr->NwReference [LNG] &&
						   subPtr->NwReference [LAT] < parPtr->NwReference [LAT];
				if (overlap)
				{
					thisPtr->SubOverlap = TRUE;		/* for testing ease */
				}
			}
		}
	
		if (thisPtr->SubOverlap != 0)
		{
			for (idx = 0;idx < thisPtr->SubCount;idx += 1)
			{
				subPtr = &thisPtr->SubGridDir [idx];
				subPtr->Cacheable = FALSE;
			}
		}
	}

	/* OK, we should be ready to rock and roll.  We close the Stream until
	   we actually need it.  Often, we get constructed just so there is a
	   record of the coverage afforded by the file. */
	if (stream != NULL)
	{
		CS_fclose (stream);
		stream = NULL;
	}
	csErrnam [0] = '\0';
	return 0;

error:
	if (stream != NULL)
	{
		CS_fclose (stream);
		stream = NULL;
	}
	if (thisPtr->SubGridDir != NULL)
	{
		CS_free (thisPtr->SubGridDir);
		thisPtr->SubGridDir = NULL;
	}
	thisPtr->HdrRecCnt = 0;
	thisPtr->SubCount = 0;
	thisPtr->RecSize = 16;
	thisPtr->CellIsValid = FALSE;
	thisPtr->SubOverlap = (short)((flags & 0x01) != 0);
	thisPtr->IntType = csNTv2TypeNone;
	thisPtr->BufferSize = bufferSize;
	thisPtr->sourceId [0] = '\0';
	if (thisPtr->BufferSize <= 0) thisPtr->BufferSize = csNTv2BufrSz;
	if (thisPtr->BufferSize <= 4096) thisPtr->BufferSize = 4096;
	CSinitNTv2GridCell (&thisPtr->longitudeCell);
	CSinitNTv2GridCell (&thisPtr->latitudeCell);
	return -1;
}
Beispiel #9
0
/* Given a lat/long, we extract the grid cell which covers the point. */
int CSextractJgd2kGridFile (struct cs_Japan_ *thisPtr,Const double* sourceLL)
{
	extern char csErrnam [];
	extern double cs_Sec2Deg;

	int flag;
	size_t rdCnt;

	long32_t startFP;
	ulong32_t meshCode;
	ulong32_t iLng, iLat;

	double density;
	double swLL [2], seLL [2], neLL [2], nwLL [2];

	struct csJgd2kGridRecord_ srchKey;
	struct csJgd2kGridRecord_ swRec, seRec, neRec, nwRec;

	/* If the cuirrent grid cell objects saved within this object cover
	   the provided point, there is no need to repeat the bulk of this
	   function.  Once a point is converted, it is quite liekly that the
	   sunsequent point is in the same grid cell, so this check usually
	   saves mucho processing time. */
	if (CStestCoverage (&thisPtr->lngCell.coverage,sourceLL) != 0.0)
	{
		/* The longitude cell covers this point.  The latitude cell always
		   covers the exact same cell, no need to waste time checking it.
		   
		   Since we already have the appropriate grid cell available, we're
		   done.  */
		return csGRIDI_ST_OK;
	}

	/* Ok, the provided point is not in the same cell as the last point.  We
	   have lots of work to do; but only if the point provided is within the
	   rectangular region of coverage of the file.  While this check is usually
	   performed prior to calling this function, we repeat it again here as
	   it precludes a lot of overflow and bounds checking below.  Thus, the
	   price of the this additional check is fully paid for. */
	density = CStestCoverage (&thisPtr->coverage,sourceLL);
	if (density == 0.0)
	{
		/* Out of range.  This check eliminates the need for lots of error
		   checking below */
		return csGRIDI_ST_COVERAGE;
	}

	/* Open the binary image file if is isn't open already. */
	if (thisPtr->strm == NULL)
	{
		/* Open the binary file, since it isn't open already. */
		thisPtr->strm = CS_fopen (thisPtr->filePath,_STRM_BINRD);
		if (thisPtr->strm == NULL)
		{
			CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
			CS_erpt (cs_DTC_FILE);
			return csGRIDI_ST_SYSTEM;
		} 
	}

	/* Note, we don't use a buffer (anymore, we used to).  If bufferSize
	   is not zero, we instuct the OS to use a buffer of the indicated size. */
	if (thisPtr->bufferSize > 128L /*&& thisPtr->dataBuffer == NULL*/)
	{
		setvbuf (thisPtr->strm,NULL,_IOFBF,(size_t)thisPtr->bufferSize);
	}

	/* The first two records in the binary image are the min/max of the file
	   coverage.  Thus, we instruct the binary search function to use the
	   thrid record as the front end of the binary search using the startFP
	   variable. */
	startFP = sizeof (struct csJgd2kGridRecord_) + sizeof (struct csJgd2kGridRecord_);

	/* Locate and read the four corners.  This is quite brutal, but
	   this is the only general way to determine coverage is to see
	   if all four corners of the cell exist.  This is a very specific
	   feature of the Japanese file.  This means that the data file does
	   not need to contain thousands of bogus values covering the
	   Pacific Ocean.  Unlike many other nations, a rectangular coverage
	   region does not work well for Japan.

	   The rather strange nature of this code is the result of our
	   desire to keep all information about the nature of the 'mesh'
	   in the two functions defined above.
	   
	   The sequence which appears immediately below produces the mesh code
	   of the southwest corner of the desired grid cell. */
	meshCode = CSjpnLlToMeshCode (sourceLL);
	if (meshCode == 0UL)
	{
		return csGRIDI_ST_SYSTEM;
	}
	CSjpnMeshCodeToLl (swLL,meshCode);
	iLng = (ulong32_t)CS_degToSec (swLL [0]);
	iLat = (ulong32_t)CS_degToSec (swLL [1]);

	srchKey.meshCode = meshCode;
	flag = CS_bins (thisPtr->strm,startFP,-1L,sizeof (struct csJgd2kGridRecord_),&srchKey,(CMPFUNC_CAST)CScompareJgd2kGridRecord);
	if (flag < 0) return -1;
	if (!flag) return 1;			/* mesh code does not exist in the file, thus no coverage for this point */
	rdCnt = CS_fread (&swRec,1,sizeof (swRec),thisPtr->strm);
	if (rdCnt != sizeof (swRec))
	{
		CS_erpt (cs_IOERR);
		return csGRIDI_ST_SYSTEM;
	}

	/* Now for the southeast corner of the cell. */
	iLng += 45;
	seLL [0] = (double)iLng * cs_Sec2Deg;
	seLL [1] = (double)iLat * cs_Sec2Deg;
	meshCode = CSjpnLlToMeshCode (seLL);
	if (meshCode == 0UL) return -1;
	srchKey.meshCode = meshCode;
	flag = CS_bins (thisPtr->strm,0L,-1L,sizeof (struct csJgd2kGridRecord_),&srchKey,(CMPFUNC_CAST)CScompareJgd2kGridRecord);
	if (flag < 0) return -1;
	if (!flag) return 1;			/* mesh code does not exist in the file, thus no coverage for this point */
	rdCnt = CS_fread (&seRec,1,sizeof (seRec),thisPtr->strm);
	if (rdCnt != sizeof (seRec))
	{
		CS_erpt (cs_IOERR);
		return csGRIDI_ST_SYSTEM;
	}

	/* The northeast corner of the grid cell. */
	iLat += 30;
	neLL [0] = (double)iLng * cs_Sec2Deg;
	neLL [1] = (double)iLat * cs_Sec2Deg;
	meshCode = CSjpnLlToMeshCode (neLL);
	if (meshCode == 0UL) return -1;
	srchKey.meshCode = meshCode;
	flag = CS_bins (thisPtr->strm,0L,-1L,sizeof (struct csJgd2kGridRecord_),&srchKey,(CMPFUNC_CAST)CScompareJgd2kGridRecord);
	if (flag < 0) return -1;
	if (!flag) return 1;			/* mesh code does not exist in the file, thus no coverage for this point */
	rdCnt = CS_fread (&neRec,1,sizeof (neRec),thisPtr->strm);
	if (rdCnt != sizeof (neRec))
	{
		CS_erpt (cs_IOERR);
		return csGRIDI_ST_SYSTEM;
	}

	/* Finally, the northwest corner of the grid cell. */
	iLng -= 45;
	nwLL [0] = (double)iLng * cs_Sec2Deg;
	nwLL [1] = (double)iLat * cs_Sec2Deg;
	meshCode = CSjpnLlToMeshCode (nwLL);
	if (meshCode == 0UL) return -1;
	srchKey.meshCode = meshCode;
	flag = CS_bins (thisPtr->strm,0L,-1L,sizeof (struct csJgd2kGridRecord_),&srchKey,(CMPFUNC_CAST)CScompareJgd2kGridRecord);
	if (flag < 0) return -1;
	if (!flag) return 1;			/* mesh code does not exist in the file, thus no coverage for this point */
	rdCnt = CS_fread (&nwRec,1,sizeof (nwRec),thisPtr->strm);
	if (rdCnt != sizeof (nwRec))
	{
		CS_erpt (cs_IOERR);
		return csGRIDI_ST_SYSTEM;
	}

	/* If we're still here, we have all four corners and finally, at last,
	   know that we have coverage for the provided point. */

	/* Populate the two cell structures involved.  Note that these cells have their
	   own rather general coverage structures.  Thus, on the next transformation
	   involving this object, we can quickly determine if the new point is in the same
	   cell as the last point (quite likely), and all of the above can be skipped.  */
	CSsetCoverage (&thisPtr->lngCell.coverage,swLL,neLL);
	thisPtr->lngCell.coverage.density = thisPtr->ewDelta;
	thisPtr->lngCell.currentAA = (double)swRec.deltaLng / 100000.0;
	thisPtr->lngCell.currentBB = (double)(seRec.deltaLng - swRec.deltaLng) / 100000.0;
	thisPtr->lngCell.currentCC = (double)(nwRec.deltaLng - swRec.deltaLng) / 100000.0;
	thisPtr->lngCell.currentDD = (double)(swRec.deltaLng - seRec.deltaLng - nwRec.deltaLng + neRec.deltaLng) / 100000.0;

	CSsetCoverage (&thisPtr->latCell.coverage,swLL,neLL);
	thisPtr->latCell.coverage.density = thisPtr->nsDelta;
	thisPtr->latCell.currentAA = (double)swRec.deltaLat / 100000.0;
	thisPtr->latCell.currentBB = (double)(seRec.deltaLat - swRec.deltaLat) / 100000.0;
	thisPtr->latCell.currentCC = (double)(nwRec.deltaLat - swRec.deltaLat) / 100000.0;
	thisPtr->latCell.currentDD = (double)(swRec.deltaLat - seRec.deltaLat - nwRec.deltaLat + neRec.deltaLat) / 100000.0;

	/* Identify the source of data for the grid cell. */
	CS_stncp (thisPtr->lngCell.sourceId,thisPtr->fileName,sizeof (thisPtr->lngCell.sourceId));
	CS_stncp (thisPtr->latCell.sourceId,thisPtr->fileName,sizeof (thisPtr->lngCell.sourceId));

	/* We're done, some one else does the actual calculation. */
	return csGRIDI_ST_OK;
}
Beispiel #10
0
/* This function creates a binary version of the Jgd2k file if it doesn't
   exist, or if the date on the binary file is older than or equal to
   that of the primary text file.  Note, that this function uses the path name
   in the provided object, and modifies it to point to the binary file which
   is then created if necessary.

   This function is implemented as records in the ASCII text file may not be
   of fixed length, there can be a million of them, and there is no guarantee
   that the records in the text file will be properly sorted.  The binary
   file enables random access to the data file for decent performance without
   eating up 12MB of RAM. */
int CSmakeBinaryJgd2kFile (struct cs_Japan_* thisPtr)
{
	extern char cs_ExtsepC;
	extern char csErrnam [];
	extern double cs_Zero;

	int st;
	cs_Time_ aTime, bTime;

	size_t wrCnt;

	char *cp1, *cp2;
	csFILE *aStrm, *bStrm;

	long32_t tempL;
	long32_t dblFrmt;
	ulong32_t meshCode;

	double lngTmp, latTmp;
	double mesh_ll [2];

	char lineBufr [128];
	char binaryPath [MAXPATH];

	struct csJgd2kGridRecord_ gridRec;
	struct csJgd2kGridRecord_ minRec;
	struct csJgd2kGridRecord_ maxRec;

	/* We will write two records to the file with bogus mesh codes.  These
	   records will carry the minimum (i.e. southwest) longitude and latitude
	   and the maximum (i.e. northeast) longitude and latitude of the data in
	   the file.  This is an attempt to make the file format something which
	   does not inherently imply applicability to Japanese geography.
	   
	   The bogus mesh codes were devised such that the min/max will be the
	   first two records in the file, thus easily accessible.  For these two
	   special records, the deltaLng and DeltaLat fields carry absolute 
	   longitude and latitude in seconds. */
	minRec.meshCode = 1UL;
	minRec.deltaLat = (long32_t)( 90 * 3600);
	minRec.deltaLng = (long32_t)(180 * 3600);
	maxRec.meshCode = 2UL;
	maxRec.deltaLat = (long32_t)( -90 * 3600);
	maxRec.deltaLng = (long32_t)(-180 * 3600);

	/* Prepare for an error of some sort. */
	aStrm = bStrm = NULL;
	lngTmp = latTmp = cs_Zero;

	/* Manufacture the name of the binary file. */
	CS_stncp (binaryPath,thisPtr->filePath,sizeof (binaryPath));
	cp1 = strrchr (binaryPath,cs_ExtsepC);
	if (cp1 == NULL) 
	{
		CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
		CS_erpt (cs_DTC_FILE);
		goto error;
	}
	CS_stcpy ((cp1 + 1),"_par");

	bTime = CS_fileModTime (binaryPath);
	/* Build a new binary file only if it doesn't exist yet. */
	if (0 == bTime)
	{
		/* Determine the last modification time for the two files.  Zero time value
		   means the file does not exist. */
		aTime = CS_fileModTime (thisPtr->filePath);
		if (aTime == 0)
		{
			/* The indicated source file does not exist, not uncommon among the
			   error conditions possible. */
			CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
			CS_erpt (cs_DTC_FILE);
			goto error;
		}

		/* Here to create a, possibly new, binary version of the Jgd2k file,
		   typically named "TKY2JGD.par".  To follow the general design
		   theme, we assume there can be several files, and there is no fixed
		   name for any of the files.  At this particular point, of course,
		   we're only dealing with one file, the file whose name was provided.
		   
		   We write one csJgd2kGridRecord structure	for each line of text that
		   we read.   Of course, we need to skip the first two lines (usually)
		   in the file as they are of the mets-data variety. */
		aStrm = CS_fopen (thisPtr->filePath,_STRM_TXTRD);
		if (aStrm == NULL)
		{
			/* This could happen if the file exists, but for some reason we
			   are denied permission to read the file.*/
			CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
			CS_erpt (cs_DTC_FILE);
			goto error;
		}

		/* The mode of the following open will truncate any existing file, and
		   create a new binary file if necessary. */
		bStrm = CS_fopen (binaryPath,_STRM_BINWR);
		if (bStrm == NULL)
		{
			CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
			CS_erpt (cs_FL_OPEN);
			goto error;
		}

		/* If we're still here, we can copy the file, converting it to binary
		   form as we do.  While doing so, we'll convert each mesh code to
		   latitude and longitude form and accumulate an estimate of the
		   coverage of the file. */
		while (CS_fgets (lineBufr,sizeof (lineBufr),aStrm) != NULL)
		{
			/* Parse the information is in a record. */
			meshCode = CS_strtoul (lineBufr,&cp1,10);
			
			/* The first two lines of the files we've seen contain labels and
			   other data.  We use the following to filter these out.  This may
			   need to be improved should new versions of the file include some
			   other form of header. */
			if (meshCode == 0 || meshCode == 0xffffffffUL) continue;
			
			/* Accumulate a bounding box (or minimum and maximum as us old
			   farts used to call it) so we have a rough estimate of the
			   coverage of the file. */
			CSjpnMeshCodeToLl (mesh_ll,meshCode);			
			if (mesh_ll [LNG] < -180.0 || mesh_ll [LNG] > 180.0 ||
				mesh_ll [LAT] <  -90.0 || mesh_ll [LAT] > 90.0)
			{
				/* Bogus mesh code.  We could consider this to be meta-data
				   that slipped through the code immediately above, or that
				   the file is invalid.  For now, we consider it to be the
				   latter:  The file is not a validly formatted data file. */
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			tempL = (long32_t)(mesh_ll [LNG] * 3600 + 0.01);
			if (tempL < minRec.deltaLng) minRec.deltaLng = tempL; 
			if (tempL > maxRec.deltaLng) maxRec.deltaLng = tempL; 
			tempL = (long32_t)(mesh_ll [LAT] * 3600 + 0.01);
			if (tempL < minRec.deltaLat) minRec.deltaLat = tempL; 
			if (tempL > maxRec.deltaLat) maxRec.deltaLat = tempL; 

			/* Separate the two data values.  We avoid strtod as it is
			   locale dependent and the data file is not. */			
			while (*cp1 == ' ') cp1++;
			cp2 = strchr (cp1,' ');
			*cp2++ = '\0';
			while (*cp2 == ' ') cp2++;

			dblFrmt = CSatof (&latTmp,cp1,'.',',',':');
			if (dblFrmt >= 0)
			{
				dblFrmt = CSatof (&lngTmp,cp2,'.',',',':');
			}
			if (dblFrmt < 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Build a new record in the array. */
			gridRec.meshCode = meshCode;
			
			/* NTO 30 Oct 2008, Trac # 13
			   The following was necessiatated by Linux.  It appears that on the
			   Linux platform (or some of them, anyway), the rounding of doubles
			   (especially negative ones) is different than what you will see on
			   WIN32 platforms.  Which one is correct is of no concern to me,
			   only that they are different. */
			latTmp *= 100000.0;
			latTmp += (latTmp >= 0.0) ? 0.1 : -0.1;
			lngTmp *= 100000.0;
			lngTmp += (lngTmp >= 0.0) ? 0.1 : -0.1;
			/* End Linux fix, Trac #13 */

			gridRec.deltaLat = (long32_t)(latTmp);
			gridRec.deltaLng = (long32_t)(lngTmp);
			wrCnt = CS_fwrite (&gridRec,sizeof (gridRec),1,bStrm);
			if (wrCnt != 1)
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
		}

		/* If we're still here, we write minRec and maxRec to the file so we
		   have a record of the coverage of the file. */
		wrCnt =	CS_fwrite (&minRec,sizeof (minRec),1,bStrm);
		if (wrCnt != 1)
		{
			CS_erpt (cs_IOERR);
			goto error;
		}
		wrCnt = CS_fwrite (&maxRec,sizeof (maxRec),1,bStrm);
		if (wrCnt != 1)
		{
			CS_erpt (cs_IOERR);
			goto error;
		}

		/* Close the file streams.  We're going to open the binary file back
		   up immediately, but have found this redundant close and open to
		   produce more reliable operation cross platforms. */
		CS_fclose (aStrm);
		aStrm = NULL;
		st = CS_fclose (bStrm);
		bStrm = NULL;

		/* OK, we need to sort the file by mesh codes so we can use a binary
		   search algorithm on it.  This should also cause the min/max records
		   to end up being the first two records in the file. This is very
		   convenient.

		   Note that the position of any one record in the file with respect
		   to any other record in the file is immaterial in this file format.
		   Thus, we can reorder the file any way we want to.  The original
		   code was written in the Windows 95 era, so the current scheme may
		   look rather dumb.  Nevertheless, it works and I have no motivation
		   to fix it. */
		bStrm = CS_fopen (binaryPath,_STRM_BINUP);
		if (bStrm == NULL)
		{
			CS_stncp (csErrnam,binaryPath,MAXPATH);
			CS_erpt (cs_FL_OPEN);
			goto error;
		}
		st = CS_ips (bStrm,sizeof (gridRec),0L,(CMPFUNC_CAST)CScompareJgd2kGridRecord);
		CS_fclose (bStrm);
		bStrm = NULL;
		if (st < 0) goto error;
		if (st == 1) st = csGRIDI_ST_OK;	/* CS_ips returns 1 for success, for historical reasons. */

		/* OK, now we're really done. */
	}

	/* If all that was done successfully, we change the name of
	   the file and return success. */
	CS_stncp (thisPtr->filePath,binaryPath,sizeof (thisPtr->filePath));
	return csGRIDI_ST_OK;
error:
	if (aStrm != NULL)
	{
		CS_fclose (aStrm);
		aStrm = NULL;
	}
	if (bStrm != NULL)
	{
		CS_fclose (bStrm);
		bStrm = NULL;
	}
	return csGRIDI_ST_SYSTEM;
}
Beispiel #11
0
struct cs_Japan_* CSnewJgd2kGridFile (Const char *path,long32_t bufferSize,ulong32_t flags,double density)
{
	extern double cs_Sec2Deg;		/* 1.0 / 3600.0 */
	extern char cs_DirsepC;
	extern char csErrnam [];

	int st;
	size_t rdCnt;

	char *cp;
	csFILE *bStrm = NULL;
	struct cs_Japan_ *thisPtr = NULL;

	char lineBufr [MAXPATH];

	struct csJgd2kGridRecord_ minRec;
	struct csJgd2kGridRecord_ maxRec;

	/* Allocate the object structure. */
	thisPtr = CS_malc (sizeof (struct cs_Japan_));
	if (thisPtr == NULL)
	{
		CS_erpt (cs_NO_MEM);
		goto error;
	}

	/* Initialize. */
	CSinitCoverage (&thisPtr->coverage);
	thisPtr->ewDelta = ( 45.0 / 3600.0);
	thisPtr->nsDelta = ( 30.0 / 3600.0);
	thisPtr->coverage.density = thisPtr->ewDelta;
	//if (thisPtr->nsDelta > thisPtr->ewDelta) 
	//{
	//	thisPtr->coverage->density = thisPtr->nsDelta;
	//}

	thisPtr->strm = NULL;
	thisPtr->bufferSize = 64 * sizeof (struct csJgd2kGridRecord_);
	if (bufferSize > 0UL) thisPtr->bufferSize = bufferSize;
	thisPtr->dataBuffer = NULL;
	CSinitGridCell (&thisPtr->lngCell);
	CSinitGridCell (&thisPtr->latCell);
	thisPtr->lngCell.deltaLng = thisPtr->ewDelta;
	thisPtr->lngCell.deltaLat = thisPtr->nsDelta;
	thisPtr->latCell.deltaLng = thisPtr->ewDelta;
	thisPtr->latCell.deltaLat = thisPtr->nsDelta;
	thisPtr->filePath [0] = '\0';
	thisPtr->fileName [0] = '\0';

	/* Capture the file name, etc. */
	CS_stncp (thisPtr->filePath,path,sizeof (thisPtr->filePath));
	CS_stncp (lineBufr,path,sizeof (thisPtr->filePath));
	cp = strrchr (lineBufr,cs_DirsepC);
	if (cp != NULL) CS_stncp (thisPtr->fileName,(cp + 1),sizeof (thisPtr->fileName));
	else CS_stncp (thisPtr->fileName,lineBufr,sizeof (thisPtr->fileName));

	/* Save the name for error message, audit trail purposes. */
	CS_stncp (thisPtr->lngCell.sourceId,thisPtr->fileName,sizeof (thisPtr->lngCell.sourceId));
	CS_stncp (thisPtr->latCell.sourceId,thisPtr->fileName,sizeof (thisPtr->latCell.sourceId));

	/* Make a binary file which we can use.  Note this verifies the existence
	   of the file. */
	st = CSmakeBinaryJgd2kFile (thisPtr);
	if (st != 0)
	{
		CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
		CS_erpt (cs_DTC_FILE);
		goto error;
	}

	/* If we're still here, we have a binary image of the named .par file.
	   We open it and extract the first two records which should be the
	   min and max of the coverage of the file. */
	bStrm = CS_fopen (thisPtr->filePath,_STRM_BINRD);
	if (bStrm == NULL)
	{
		CS_stncp (csErrnam,thisPtr->filePath,MAXPATH);
		CS_erpt (cs_FL_OPEN);
		goto error;
	}
	rdCnt = CS_fread (&minRec,sizeof (minRec),1,bStrm);
	if (rdCnt != 1)
	{
		CS_erpt (cs_IOERR);
		goto error;
	}
	rdCnt = CS_fread (&maxRec,sizeof (maxRec),1,bStrm);
	if (rdCnt != 1)
	{
		CS_erpt (cs_IOERR);
		goto error;
	}
	CS_fclose (bStrm);
	bStrm = NULL;

	if (minRec.meshCode != 1L || maxRec.meshCode != 2L)
	{
		CS_stncp (csErrnam,"CS_japan::1",MAXPATH);
		CS_erpt (cs_ISER);
		goto error;
	}

	/* Capture the min/max of the the file coverage in the coverage object. */
	thisPtr->coverage.southWest [LNG] = (double)(minRec.deltaLng) * cs_Sec2Deg;
	thisPtr->coverage.southWest [LAT] = (double)(minRec.deltaLat) * cs_Sec2Deg;
	thisPtr->coverage.northEast [LNG] = (double)(maxRec.deltaLng) * cs_Sec2Deg;
	thisPtr->coverage.northEast [LAT] = (double)(maxRec.deltaLat) * cs_Sec2Deg;

	/* We leave the binary file closed until such time as the host application
	   requests a conversion which actually requires access to the file.  It is
	   not uncommon for geodetic transformations to list grid interpolation
	   files in their definition which are rarely used. */
	return thisPtr;
error:
	if (bStrm != NULL)
	{
		CS_fclose (bStrm);
		bStrm = NULL;
	}
	CSdeleteJgd2kGridFile (thisPtr);
	return NULL;
}
Beispiel #12
0
int CSjapanQ  (struct csGeodeticXfromParmsFile_* fileParms,Const char* dictDir,int err_list [],int list_sz)
{
	extern char cs_DirsepC;
	extern char cs_ExtsepC;

	int err_cnt;

	char *cp;
	csFILE* strm;

	char meshCode [] = "Meshcode";
	char line1Buffer [256];
	char line2Buffer [256];
	char line3Buffer [256];
	char pathBuffer [MAXPATH];

	cp = fileParms->fileName;
	if (*cp == '.' && *(cp + 1) == cs_DirsepC)
	{
		CS_stncp (pathBuffer,dictDir,sizeof (pathBuffer));
		CS_stncat (pathBuffer,cp,MAXPATH);
	}
	else
	{
		CS_stncp (pathBuffer,cp,MAXPATH);
	}

	/* We will return (err_cnt + 1) below. */
	err_cnt = -1;
	if (err_list == NULL) list_sz = 0;

	/* Verify that the file exists and that the format appears to be correct. */
	strm = CS_fopen (pathBuffer,_STRM_TXTRD);
	if (strm != NULL)
	{
		CS_fgets (line1Buffer,sizeof (line1Buffer),strm);	
		CS_fgets (line2Buffer,sizeof (line2Buffer),strm);	
		CS_fgets (line3Buffer,sizeof (line3Buffer),strm);	
		CS_fclose (strm);
		strm = NULL;

		if (!CS_stristr (line1Buffer,meshCode) &&
			!CS_stristr (line2Buffer,meshCode) &&
			!CS_stristr (line3Buffer,meshCode))
		{
			/* The pohrase meshcode was not found anywhere on the first three
			   lines, we assume this is not a ".par" file. */
			if (++err_cnt < list_sz) err_list [err_cnt] = cs_DTQ_FORMAT;
		}
	}
	else
	{
		//the txt file didn't exist - so, check whether at least the binary file does
		cp = strrchr (pathBuffer,cs_ExtsepC);
		if (cp == NULL) 
		{
			if (++err_cnt < list_sz) err_list [err_cnt] = cs_DTQ_FILE;
		}
		else
		{
			CS_stcpy ((cp + 1),"_par");
			if (0 != CS_access(pathBuffer, 4))
			{
				if (++err_cnt < list_sz) err_list [err_cnt] = cs_DTQ_FILE;
			}
		}
	}

	return (err_cnt + 1);
}
Beispiel #13
0
int EXP_LVL3 CS_dtdel (struct cs_Dtdef_ *dtdef)
{
    extern char csErrnam [];
    extern char cs_Dir [];
    extern short cs_Protect;

    short cs_time;

    int st;
    csFILE *old_strm;
    csFILE *new_strm;
    int rd_st;
    int crypt;
    size_t wr_cnt;

    cs_magic_t magic;

    struct cs_Dtdef_ *my_ptr;

    char tmp_nam [MAXPATH];

    __ALIGNMENT__1		/* For some versions of Sun compiler. */

    struct cs_Dtdef_ cpy_buf;

    /* Capture the current time. */
    cs_time = (short)((CS_time ((cs_Time_ *)0) - 630720000L) / 86400L);

    /* Prepare for an error. */
    new_strm = NULL;
    old_strm = NULL;
    my_ptr = NULL;
    tmp_nam [0] = '\0';

    /* Adjust the name and make sure it is all upper case.
       By convention, datum names are case insensitive. */
    st = CS_nampp (dtdef->key_nm);
    if (st != 0) goto error;

    /* Get a pointer to the existing definition. If it doesn't
       exist, we're all done. */
    my_ptr = CS_dtdef (dtdef->key_nm);
    if (my_ptr == NULL)
    {
        goto error;
    }

    /* See if this definition is protected.  If so, we have to
       leave it alone. If cs_Protect < 0, there is no protection. */
    if (cs_Protect >= 0)
    {
        if (my_ptr->protect == 1)
        {
            CS_stncp (csErrnam,my_ptr->key_nm,MAXPATH);
            CS_erpt (cs_DT_PROT);
            goto error;
        }
        if (cs_Protect > 0)
        {
            /* Here if user definition protection is
               enabled. */
            if (my_ptr->protect < (cs_time - cs_Protect))
            {
                CS_stncp (csErrnam,my_ptr->key_nm,MAXPATH);
                CS_erpt (cs_DT_UPROT);
                goto error;
            }
        }
    }
    CS_free (my_ptr);
    my_ptr = NULL;

    /* Make sure the entry that we have been provided is marked as
       unencrypted so that the comparison function will work. */
    dtdef->fill [0] = '\0';

    /* Open up the datum dictionary file and verify its
       magic number. */
    old_strm = CS_dtopn (_STRM_BINRD);
    if (old_strm == NULL)
    {
        goto error;
    }

    /* Create a temporary file for the new dictionary. */
    st = CS_tmpfn (tmp_nam);
    if (st != 0)
    {
        goto error;
    }
    new_strm = CS_fopen (tmp_nam,_STRM_BINWR);
    if (new_strm == NULL)
    {
        CS_erpt (cs_TMP_CRT);
        goto error;
    }

    /* Copy the file, skipping the entry to be deleted.  First
       we must deal with the magic number. */
    magic = cs_DTDEF_MAGIC;
    CS_bswap (&magic,"l");
    wr_cnt = CS_fwrite ((char *)&magic,1,sizeof (magic),new_strm);
    if (wr_cnt != sizeof (magic))
    {
        if (CS_ferror (new_strm)) CS_erpt (cs_IOERR);
        else					  CS_erpt (cs_DISK_FULL);
        goto error;
    }

    /* Now we copy the file.  If the existing record was encrypted,
       we encrypt the record which we write. */
    while ((rd_st = CS_dtrd (old_strm,&cpy_buf,&crypt)) > 0)
    {
        if (CS_dtcmp (&cpy_buf,dtdef) != 0)
        {
            if (CS_dtwr (new_strm,&cpy_buf,crypt))
            {
                goto error;
            }
        }
    }
    if (rd_st != 0)
    {
        /* The copy loop terminated due to an error. */
        goto error;
    }

    /* Close up, remove the old dictionary and rename the
       new dictionary. */
    CS_fclose (new_strm);
    new_strm = NULL;
    CS_dtDictCls (old_strm);
    old_strm = NULL;
    st = CS_remove (cs_Dir);
    if (st != 0)
    {
        strcpy (csErrnam,cs_Dir);
        CS_erpt (cs_UNLINK);
        goto error;
    }
    st = CS_rename (tmp_nam,cs_Dir);
    if (st != 0) goto error;

    /* We're done. */
    return (0);

error:
    if (new_strm != NULL)
    {
        /* tmp_nam can never be uninitialized if new_fd >= 0 */
        CS_fclose (new_strm);
        CS_remove (tmp_nam);				/*lint !e534 !e645 */
    }
    if (old_strm != NULL) CS_dtDictCls (old_strm);
    if (my_ptr != NULL) CS_free (my_ptr);
    return (-1);
}
Beispiel #14
0
csFILE * EXP_LVL3 CS_dtopn (Const char *mode)
{
    extern char cs_Dir [];
    extern char *cs_DirP;
    extern char cs_Dtname [];
    extern char csErrnam [];

    size_t rdCnt;

    csFILE *strm = NULL;

    cs_magic_t magic;

    if (cs_DtStream != 0)
    {
        if (!CS_stricmp (mode,_STRM_BINRD))
        {
            strm = cs_DtStream;
            CS_fseek (strm,(long)sizeof (magic),SEEK_SET);
        }
        else
        {
            CS_fclose (cs_DtStream);
            cs_DtStream = NULL;
        }
    }
    if (strm == NULL)
    {
        strcpy (cs_DirP,cs_Dtname);
        strm = CS_fopen (cs_Dir,mode);
        if (strm != NULL)
        {
            rdCnt = CS_fread ((char *)&magic,1,sizeof (magic),strm);
            if (rdCnt != sizeof (magic))
            {
                if (CS_ferror (strm)) CS_erpt (cs_IOERR);
                else				  CS_erpt (cs_INV_FILE);
                CS_fclose (strm);
                strm = NULL;
                strcpy (csErrnam,cs_Dir);
            }
            else
            {
                CS_bswap (&magic,"l");
                if (magic != cs_DTDEF_MAGIC)
                {
                    CS_fclose (strm);
                    strm = NULL;
                    strcpy (csErrnam,cs_Dir);
                    CS_erpt (cs_DT_BAD_MAGIC);
                }
                else if (!strcmp (mode,_STRM_BINRD))
                {
                    cs_DtStream = strm;
                }
            }
        }
        else
        {
            strcpy (csErrnam,cs_Dir);
            CS_erpt (cs_DTDICT);
        }
    }
    return (strm);
}
Beispiel #15
0
/* Interpolation Calculator
	Due to a bust in the file format, we do not buffer up grid cells and stuff.
	There are a couple of sub-grids which overlap other grids in such a way that
	buffering can cause errors.  So, at least until (if ever) the data file is
	corrected, we do no buffering of the grid cells.

	Also, this file format is being adopted by others, like the Aussie's.  We
	don't know what they are going to do.  So to be safe, NO BUFFERING OF GRID
	CELLS.

	Also, due to the sub-grid nature of the data file, we do not buffer the
	data file in any special way; we simply use normal stream buffering.
*/
int CScalcGridFileCa2 (struct csGridFileCa2_* __This,double deltaLL [2],Const double source [2])
{
	extern double cs_Zero;				/* 0.0 */
	extern double cs_LlNoise;			/* 1.0E-12 */
	extern char csErrnam [];

	short idx;
	short parIdx;
	short onLimit;
	unsigned short eleNbr, rowNbr;

	int seekStat;
	int rtnValue;
	size_t readCnt;
	long32_t filePosition;
	struct csGridFileCa2SubGrid_ *subPtr;
	struct csGridFileCa2SubGrid_ *cvtPtr;

	double bestCellSize;
	double wpLL [2];
	double swCell [2];

	struct TcsCaNTv2Data southEast;
	struct TcsCaNTv2Data southWest;
	struct TcsCaNTv2Data northEast;
	struct TcsCaNTv2Data northWest;

	/* Until we know differently. */
	__This->CellIsValid = FALSE;

	/* In case of an error.  This saves duplication of this many many times. */
	CS_stncp (csErrnam,__This->FilePath,MAXPATH);

	/* Remember, source is East Positive.  The CaNTv2 file is West Positive. */
	wpLL [LNG] = -source [LNG];
	wpLL [LAT] =  source [LAT];

	/* Locate the appropriate sub-grid.  If there is none, than there is no
	   coverage.  There are two algorithms:  the original one and one invented
	   to cater to the Spaniards, maybe someothers in the future.
	   
	   In the original alghorithm, we search through the top level of parent
	   grids looing for coverage.  The top level parents are those which have no
	   parent.  If none is found, there is no coverage.  If we locate a parent
	   which provides coverage, we examine all children of that parent looking
	   for a sub-grid; and so on.
	   
	   In the Spanish algorithm, we search all grids, and choose the grid which
	   produces the smallest cell size.  This is necessary as the grids are
	   allowed to overlap in the Spanish variation. */

	cvtPtr = NULL;			/* NULL says no coverage (yet). */
	if (__This->SubOverlap == 0)
	{
		parIdx = -1;
		/* The Canadian algorithm. We loop, only considering those
			sub-grids whose parent index match parIdx. */
		for (idx = 0;idx < __This->SubCount;idx += 1)
		{
			subPtr = &__This->SubGridDir [idx];

			/* The following verifies that the current sub is a child of
			   the located parent.  Also, causes children to be skipped
			   until such time as we have found a parent. */
			if (subPtr->ParentIndex != parIdx) continue;

			/* Does this sub grid cover the point we are to convert?
			   Remember, we're dealing with WEST POSITIVE longitude.
			   the SeReference & NwReference values are west positive.
			   Think of this being a transformation that applies to
			   Russia, instead of Canada. */
			if (wpLL [LNG] >= subPtr->SeReference [LNG] &&
				wpLL [LAT] >= subPtr->SeReference [LAT] &&
				wpLL [LNG] <= subPtr->NwReference [LNG] &&
				wpLL [LAT] <= subPtr->NwReference [LAT])
			{
				/* If this is a sub grid and on the northern or western
				   boundary, we do not consider it a match. */
				if (subPtr->ParentIndex >= 0 &&
					(wpLL [LNG] >= subPtr->NwReference [LNG] ||
					 wpLL [LAT] >= subPtr->NwReference [LAT])
				   )
				{
					continue;
				}
				
				/* We have a match. */
				cvtPtr = subPtr;

				/* See if this grid has one or more children. */
				if (cvtPtr->ChildIndex < 0)
				{
					/* This one has no children; use cvtPtr. */
					break;
				}

				/* This guy has children. We need to see if any of these
				   children cover the point we are converting.  Need a minus
				   one here as the loop code is going to bump idx. */
				parIdx = idx;
				idx = cvtPtr->ChildIndex - 1;
			}
		}
	}
	else
	{
		/* The Spanish variation.  We search all subgrids looking for
		   coverages.  As the sub-grids are allowed to overlap, we must
		   search them all, and we select the one which produces the
		   smallest cell size as the "appropriate" one. */
		bestCellSize = 1.0E+100;
		for (idx = 0;idx < __This->SubCount;idx += 1)
		{
			subPtr = &__This->SubGridDir [idx];

			/* Does this sub grid cover the point we are to convert?
			Remember, we're dealing with WEST POSITIVE longitude.
			the SeReference & NwReference values are west positive.
			Think of this being a transformation that applies to Russia,
			instead of Canada. */
			if (wpLL [LNG] >= subPtr->SeReference [LNG] &&
				wpLL [LAT] >= subPtr->SeReference [LAT] &&
				wpLL [LNG] <= subPtr->NwReference [LNG] &&
				wpLL [LAT] <= subPtr->NwReference [LAT])
			{
				/* Yes it does.  Getthe cell size and see if it is batter
				   than what we have found so far. */
				if (subPtr->Density < bestCellSize)
				{
					cvtPtr = subPtr;
					bestCellSize = subPtr->Density;
					onLimit = 0;
					if (fabs (wpLL [LAT] - cvtPtr->NwReference [LAT]) <= cs_LlNoise) onLimit |= 1;
					if (fabs (wpLL [LNG] - cvtPtr->NwReference [LNG]) <= cs_LlNoise) onLimit |= 2;
				}
			}
		}
		/* cvtPtr should still be null if no coverage was found, we rely on this. */
	}

	/* OK, if cvtPtr is not NULL, its a pointer to the approriate
	   sub grid for this conversion. */
	if (cvtPtr != NULL)
	{
		/* Make sure the file is opened.  It can get closed by a release. */
		if (__This->Stream == NULL)
		{
			__This->Stream = CS_fopen (__This->FilePath,_STRM_BINRD);
			if (__This->Stream == NULL)
			{
				CS_stncp (csErrnam,__This->FilePath,MAXPATH);
				CS_erpt (cs_DTC_FILE);
				goto error;
			}
			setvbuf (__This->Stream,NULL,_IOFBF,(size_t)__This->BufferSize);
		}

		/* Compute onLimit for this point and the selected sub-grid regardless
		   of how we got here.  This should now only occur at the extreme edges
		   of the entire file coverage. */
		onLimit = 0;
		if (fabs (wpLL [LAT] - cvtPtr->NwReference [LAT]) <= cs_LlNoise) onLimit |= 1;
		if (fabs (wpLL [LNG] - cvtPtr->NwReference [LNG]) <= cs_LlNoise) onLimit |= 2;

		/* Compute the elements required for the file access.  This is common to
		   all cases of "onLimit". */
		eleNbr = (unsigned short)(((wpLL [LNG] - cvtPtr->SeReference [LNG]) / cvtPtr->DeltaLng) + cs_LlNoise);
		rowNbr = (unsigned short)(((wpLL [LAT] - cvtPtr->SeReference [LAT]) / cvtPtr->DeltaLat) + cs_LlNoise);

		/* Compute the boundaries of the specific cell we dealing with, assuming
		   onLimit is zero (which is the case 99.999% of the time).  The
		   nonmenclature goes funny here as we use a grid cell structure which
		   is common to US and Canandian style files.  The craziness comes from
		   the fact that the US uses east positive longitude and the Canadians
		   use west positive latitude. */
		swCell [LNG] = cvtPtr->SeReference [LNG] + cvtPtr->DeltaLng * (double)eleNbr;
		swCell [LAT] = cvtPtr->SeReference [LAT] + cvtPtr->DeltaLat * (double)rowNbr;

		/* Build the extent portions of the grid cells.  Note that due to the
		   west positive nature of this dataset, the elements are used differently
		   than what the element names indicate.
		   
		   That is, since:
		   
		   1> the Canadians use positive west longitude, and
		   2> the US grid uses positive east lonigtudes, and
		   3> since we use the same grid cell structure for both the
		      US data and Canadian data,

		   we need to swap east and west in the nonmenclature used when
		   building a grid cell structure.  So, in thew code below, we are
		   actually putting the southeast corner in the southwest point
		   of the grid cell.  Similarly with the northwest and the
		   northeast. While we use the same grid cell structure (as we
		   must if as we cache these together in the same cache), we
		   have separate calculation routines; so this does work.
		 */
		__This->longitudeCell.coverage.southWest [LNG] = swCell [LNG];
		__This->longitudeCell.coverage.southWest [LAT] = swCell [LAT];
		__This->longitudeCell.coverage.northEast [LNG] = swCell [LNG] + cvtPtr->DeltaLng;
		__This->longitudeCell.coverage.northEast [LAT] = swCell [LAT] + cvtPtr->DeltaLat;
		__This->longitudeCell.coverage.density = cvtPtr->Density;
		__This->longitudeCell.deltaLng = cvtPtr->DeltaLng;
		__This->longitudeCell.deltaLat = cvtPtr->DeltaLat;

		__This->latitudeCell.coverage.southWest [LNG] = swCell [LNG];
		__This->latitudeCell.coverage.southWest [LAT] = swCell [LAT];
		__This->latitudeCell.coverage.northEast [LNG] = swCell [LNG] + cvtPtr->DeltaLng;
		__This->latitudeCell.coverage.northEast [LAT] = swCell [LAT] + cvtPtr->DeltaLat;
		__This->latitudeCell.coverage.density = cvtPtr->Density;
		__This->latitudeCell.deltaLng = cvtPtr->DeltaLng;
		__This->latitudeCell.deltaLat = cvtPtr->DeltaLat;

		/* We code reduce the code level here by getting smart with the onLimit
		   thing.  However, this gets very tricky.  My excuse here is that this
		   emulates the way the Canadians did it in FORTRAN. */
		if (onLimit == 0)
		{
			/* The normal case, probably about 99.99999 percent of the time.
			   Read the data into my record buffer. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * __This->RecSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Read southeast shifts. */
			readCnt = CS_fread (&southEast,1,sizeof (southEast),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southEast))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Read southwest shifts. */
			readCnt = CS_fread (&southWest,1,sizeof (southWest),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Read northeast shifts. */
			filePosition += cvtPtr->RowSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			readCnt = CS_fread (&northEast,1,sizeof (northEast),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (northEast))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Read northwest shifts. */
			readCnt = CS_fread (&northWest,1,sizeof (northWest),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (northWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Swap as necessary. */
			CS_bswap (&southEast,cs_BSWP_GridFileCa2Data);
			CS_bswap (&southWest,cs_BSWP_GridFileCa2Data);
			CS_bswap (&northEast,cs_BSWP_GridFileCa2Data);
			CS_bswap (&northWest,cs_BSWP_GridFileCa2Data);

			/* Build the grid cell AA, BB, CC, and DD values. */
			__This->longitudeCell.currentAA = southEast.del_lng;
			__This->longitudeCell.currentBB = southWest.del_lng - southEast.del_lng;
			__This->longitudeCell.currentCC = northEast.del_lng - southEast.del_lng;
			__This->longitudeCell.currentDD = northWest.del_lng - southWest.del_lng - northEast.del_lng + southEast.del_lng;

			__This->latitudeCell.currentAA = southEast.del_lat;
			__This->latitudeCell.currentBB = southWest.del_lat - southEast.del_lat;
			__This->latitudeCell.currentCC = northEast.del_lat - southEast.del_lat;
			__This->latitudeCell.currentDD = northWest.del_lat - southWest.del_lat - northEast.del_lat + southEast.del_lat;
		}
		else if (onLimit == 1)
		{
			/* Point is on the extreme northern edge of the sub-grid.  This occurs
			   ocassionally.  In this case, the "northern" boundary of the grid cell
			   doesn't exist, and we must manufacture such.  This is called a
			   virtual cell in the Canadian documentation.  */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * __This->RecSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			readCnt = CS_fread (&southEast,1,sizeof (southEast),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			readCnt = CS_fread (&southWest,1,sizeof (southWest),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southEast))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			/* Swap as necessary. */
			CS_bswap (&southEast,cs_BSWP_GridFileCa2Data);
			CS_bswap (&southWest,cs_BSWP_GridFileCa2Data);

			/* Do not attempt to read the northern boundary, it ain't there.
			   Compute the AA, BB, CC, DD values. */
			__This->longitudeCell.currentAA = southEast.del_lng;
			__This->longitudeCell.currentBB = southWest.del_lng - southEast.del_lng;
			__This->longitudeCell.currentCC = cs_Zero;
			__This->longitudeCell.currentDD = cs_Zero;

			__This->latitudeCell.currentAA = southEast.del_lat;
			__This->latitudeCell.currentBB = southWest.del_lat - southEast.del_lat;
			__This->latitudeCell.currentCC = cs_Zero;
			__This->latitudeCell.currentDD = cs_Zero;
			
			/* Adjust the grid cell boundaries to indicate that the northern
			   limits are the same as the southern limits.  I.e. a grid cell
			   that has zero height. */
			__This->longitudeCell.coverage.northEast [LAT] = __This->longitudeCell.coverage.southWest [LAT] + cs_LlNoise;
			__This->latitudeCell.coverage.northEast [LAT]  = __This->latitudeCell.coverage.southWest [LAT] + cs_LlNoise;
		}
		else if (onLimit == 2)
		{
			/* Point is on the extreme western edge of the sub-grid. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * __This->RecSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			readCnt = CS_fread (&southEast,1,sizeof (southEast),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			/* Don't read the south west, it ain't there. */

			filePosition += cvtPtr->RowSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			readCnt = CS_fread (&northEast,1,sizeof (northEast),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (northWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			/* Don't read the northwest, it ain't there. */

			CS_bswap (&southEast,cs_BSWP_GridFileCa2Data);
			CS_bswap (&northEast,cs_BSWP_GridFileCa2Data);

			__This->longitudeCell.currentAA = southEast.del_lng;
			__This->longitudeCell.currentBB = cs_Zero;
			__This->longitudeCell.currentCC = northEast.del_lng - southEast.del_lng;
			__This->longitudeCell.currentDD = cs_Zero;

			__This->latitudeCell.currentAA = southEast.del_lat;
			__This->latitudeCell.currentBB = cs_Zero;
			__This->latitudeCell.currentCC = northEast.del_lat - southEast.del_lat;
			__This->latitudeCell.currentDD = cs_Zero;

			/* Adjust the grid cell boundaries to indicate that the eastern
			   limits are the same as the western limits.  I.e. a grid cell
			   that has zero width. */
			__This->longitudeCell.coverage.northEast [LNG] = __This->longitudeCell.coverage.southWest [LNG] + cs_LlNoise;
			__This->latitudeCell.coverage.northEast [LNG]  = __This->latitudeCell.coverage.southWest [LNG] + cs_LlNoise;
		}
		else  /* onLimit == 3 */
		{
			/* Point is actually the northwestern corner of the sub-grid. */
			filePosition = cvtPtr->FirstRecord + rowNbr * cvtPtr->RowSize + eleNbr * __This->RecSize;
			seekStat = CS_fseek (__This->Stream,filePosition,SEEK_SET);
			if (seekStat != 0)
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}
			readCnt = CS_fread (&southEast,1,sizeof (southWest),__This->Stream);
			if (CS_ferror (__This->Stream))
			{
				CS_erpt (cs_IOERR);
				goto error;
			}
			if (readCnt != sizeof (southWest))
			{
				CS_erpt (cs_INV_FILE);
				goto error;
			}

			/* Don't read anything else.  There's nothing there. */
			CS_bswap (&southEast,cs_BSWP_GridFileCa2Data);

			/* Compute the AA, BB, CC, DD values. */
			__This->longitudeCell.currentAA = southEast.del_lng;
			__This->longitudeCell.currentBB = cs_Zero;
			__This->longitudeCell.currentCC = cs_Zero;
			__This->longitudeCell.currentDD = cs_Zero;

			__This->latitudeCell.currentAA = southEast.del_lat;
			__This->latitudeCell.currentBB = cs_Zero;
			__This->latitudeCell.currentCC = cs_Zero;
			__This->latitudeCell.currentDD = cs_Zero;

			/* Adjust the grid cell boundaries to indicate that the northeastern
			   limits are the same as the southwestern limits.  I.e. a grid cell
			   that has zero width and zero height. */
			__This->longitudeCell.coverage.northEast [LAT] = __This->longitudeCell.coverage.southWest [LAT] + cs_LlNoise;
			__This->latitudeCell.coverage.northEast [LAT]  = __This->latitudeCell.coverage.southWest [LAT] + cs_LlNoise;
			__This->longitudeCell.coverage.northEast [LNG] = __This->longitudeCell.coverage.southWest [LNG] + cs_LlNoise;
			__This->latitudeCell.coverage.northEast [LNG]  = __This->latitudeCell.coverage.southWest [LNG] + cs_LlNoise;
		}

		/* The cells are now valid, maybe.  We now work around a bust
		   in the Canadian grid file format. */
		__This->CellIsValid = cvtPtr->Cacheable;
		for (idx = 0;csKludgeTable [idx][0] != 0.0;idx += 1)
		{
			if (source [LNG] >= csKludgeTable [idx][0] &&
			    source [LAT] >= csKludgeTable [idx][1] &&
			    source [LNG] <= csKludgeTable [idx][2] &&
			    source [LAT] <= csKludgeTable [idx][3])
			{
				__This->CellIsValid = FALSE;
				break;
			}
		}

		/* Perform the interpolation calculation. */
		deltaLL [LNG] = CScalcGridCellCA (&__This->longitudeCell,source);
		deltaLL [LAT] = CScalcGridCellCA (&__This->latitudeCell,source);
		rtnValue = 0;
	}
	else
	{
		/* We didn't find a sub-grid.  The return value is +1 to indicate no
		   coverage.  We should, in this case, use the fall back guy. */
		deltaLL [LNG] = cs_Zero;
		deltaLL [LAT] = cs_Zero;
		rtnValue = 1;
	}
	csErrnam [0] = '\0';
	return rtnValue;
error:
	return -1;
}