/*=========================== MiscUTMConstants.m ============================*/
/* MiscUTMConstants class contains and supports the constants required for
   calculating a Universal Transverse Mercator grid point.

   For information on the underlying mathematics, refer to:

	 1- Ordinance Survey Information, "Transverse Mercator Projection,
	    Constants, Formula and Methods", March 1983

	 2- Ordinance Survey, "Tables for the Transverse Mercator Projection
	    of Ireland", 1953, reprinted 1971

   Note: Convergence could be made settable if there is ever any reason to
	 do so.

   DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights
   Reserved. For further information on terms and conditions see:
		Documentation/GISKit/Agreements-Legal-README

HISTORY
22-Feb-93  Dale Amon at GPL
	   Created.
*/

#import <math.h>
#import <MiscFoundation/MiscUTMConstants.h>
#import "_MiscError.h"

@implementation MiscUTMConstants

/*===========================================================================*/
/* Class methods */
/*===========================================================================*/
/* Initialize the class */

+ (void)initialize {[MiscUTMConstants setVersion:MISC_UTM_CONSTANTS_VERSION_ID]; return;}


/*===========================================================================*/
/* Internal methods */
/*===========================================================================*/
/* Calculate the constants used in meridian arc calculations */

- (void)setMeridianConstants
 {	double	nSqrd;		/* n squared */
	double	nCubed;		/* n cubed */

	nSqrd  = n*n;
	nCubed = nSqrd*n;

	M1 = 1.0 + n + (5.0/4.0 * nSqrd) + (5.0/4.0  * nCubed);
	M2 = (3.0 * n) + (3.0 * nSqrd) + (21.0/8.0 * nCubed);
	M3 = (15.0/8.0 * nSqrd) + (15.0/8.0 * nCubed);
	M4 = 35.0/24.0 * nCubed;
}


/*===========================================================================*/
/* Initialization methods */
/*===========================================================================*/
/* Some old grids have rounded or even incorrectly calculated values. This
   method allows the correctly calculated ones to be overriden. M1-M4 are
   also recalculated.
*/

- override_eSqrd:(double)new_eSqrd n: (double)new_n
  {
	eSqrd  = new_eSqrd;
	n      = new_n;

	[self setMeridianConstants];
	return self;
  }


/*---------------------------------------------------------------------------*/
/* DESIGNATED INITIALIZER */

- initGridName:  (NSString *) name
    trueOrigin: (double) deg_latitude : (double) deg_longitude
	inGrid: (double) e0:  (double) n0
      onSphere: (double) a0:  (double) b0
      centralMeridianScaling: (double) f0
  {	double	aa;

	[super init];

	noFree   = NO;		/* object is deletable by default */

	gridName = [name copy];

	convergence = MISC_CONVERGENCE_CRITERIA;

	/* Load primary constants */
	phi0    = [MiscCoord degreesToRadians: deg_latitude];
	lambda0 = [MiscCoord degreesToRadians: deg_longitude];
	E0   = e0; N0      = n0;
	a    = a0; b       = b0;
	F0   = f0;

	aF0 = a * F0;
	bF0 = b * F0;

	aa     = aF0*aF0;
	eSqrd  = (aa - bF0*bF0)/aa;
	n      = (aF0 - bF0)/(aF0 + bF0);

	[self setMeridianConstants];

	return self;	
  }

/*---------------------------------------------------------------------------*/
/* free the string */

- (void)dealloc
  {	if (noFree) return;

	if (gridName) free((void*)gridName);
	[super dealloc];
}


/*---------------------------------------------------------------------------*/
/* Disable use of the designated initializer from the Object class */

- init
  {	
    MISC_ERROR_BAIL;
	return self;
  }


/*---------------------------------------------------------------------------*/
/* lock a constants object against ever being free'd. This should not be undone
   because the assumption is that you are locking it because there are many
   pointers to the same object floating around.
*/

- setProtected   {noFree = YES; return self;}
- setUnprotected {noFree = NO;  return self;}


/*===========================================================================*/
/* UTM grid constants */
/*===========================================================================*/

- (NSString *) gridName             {return gridName;}


/*---------------------------------------------------------------------------*/
/* Two UTM constants objects are identical if they are either the same
   object or if their primary constants are the same. convergence is ignored
   because it may affect conversion accuracy, but does not represent a
   difference in the coordinate system.
*/

- (BOOL)isEqual:anObject
  {	MiscUTMConstants *ptr;

    if (anObject == self)			return YES;
    if ([anObject isKindOfClass:[self class]])
	{	ptr = (MiscUTMConstants*) anObject;
		if (a       != ptr->a)		return NO;
		if (b       != ptr->b)		return NO;
		if (F0      != ptr->F0)		return NO;
		if (phi0    != ptr->phi0)	return NO;
		if (lambda0 != ptr->lambda0)	return NO;
		if (E0      != ptr->E0)		return NO;
		if (N0      != ptr->N0)		return NO;

		if (aF0     != ptr->aF0)	return NO;
		if (bF0     != ptr->bF0)	return NO;

		if (eSqrd   != ptr->eSqrd)	return NO;
		if (n       != ptr->n)		return NO;

		if (M1      != ptr->M1)		return NO;
		if (M2      != ptr->M2)		return NO;
		if (M3      != ptr->M3)		return NO;
		if (M4      != ptr->M4)		return NO;
	}
    return YES;
  }


/*===========================================================================*/
/* Archive methods */
/*===========================================================================*/
- (void)encodeWithCoder:(NSCoder *)aCoder
  {	
	[aCoder encodeValuesOfObjCTypes:"ddddddddifddddddd",
			&a,&b,&F0,&phi0,&lambda0,&E0,&N0,&convergence,
			(int*)&noFree,
			&n, &aF0, &bF0, &eSqrd,&M1,&M2,&M3,&M4];
}

/*---------------------------------------------------------------------------*/
- (id)initWithCoder:(NSCoder *)aDecoder
  {	
	[aDecoder decodeValuesOfObjCTypes:"ddddddddifddddddd",
			&a,&b,&F0,&phi0,&lambda0,&E0,&N0,&convergence,
			(int*)&noFree,
			&n, &aF0, &bF0, &eSqrd,&M1,&M2,&M3,&M4];
	return self;
  }


@end
