ftp.nice.ch/pub/next/graphics/vector/MapMaker.0.9.N.bs.tar.gz#/MapMaker/proj.c

This is proj.c in view mode; [Download] [Up]

/*
** proj.c
** map projection calculation and generation routines
** for project : MapMaker  
** using NeXTStep and mach Unix.
** CPSC 414 Assignment No. 4 Project
**  
** Programmed by Bradley Head and Thomas Burkholder 
** December 1990
*/

#import "proj.h"
#import "pointdata.h"
#import "appkit/graphics.h"

/********************* THE MAP PROJECTIONS (Forward Sol'n) **********************************/

float correct(float f)
{
	if (f>=PI)
		return f-(2*PI);
	if (f < (-(PI)))
		return f+(2*PI);
	return f;
}

/*
**  Map Projection conversion functions 
*/

int Cylindrical(Point *posn, ProjParam *init, Point *pp)
{ 
float coef;

coef = init->radius*cos(init->phi1);
pp->x = (posn->x - init->lon0)*coef;
pp->y = init->radius*sin(posn->y)/cos(init->phi1);
if (pp->x > (PI*coef)) {
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {
	pp->x += ((2*PI)*coef);
	return 1;
	}
return 0;
}


int EckertIV(Point *posn, ProjParam *init, Point *pp)
{ 
float coef;

coef = .42224*init->radius*(1 + cos(posn->y - init->phi1));
pp->x = coef*(posn->x - init->lon0);
pp->y = 1.32650*init->radius*sin(posn->y - init->phi1)/cos(init->phi1);

if (pp->x  > (PI*coef)) {
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {
	pp->x += ((2*PI)*coef);
	return 1;
	} 
return 0;
}

int Mercator(Point *posn, ProjParam *init, Point *pp)
{
float coef;

coef = init->radius*0.6;			/* 0.6 scales to fit into output window with radius = 1.0 */
pp->x =coef*(posn->x - init->lon0);
pp->y = init->radius*log(tan(.785398 + posn->y/2));
if (pp->x > (PI*coef)) {
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {
	pp->x += ((2*PI)*coef);
	return 1;
	}
return 0;
}

int Mollweide(Point *posn, ProjParam *init, Point *pp)
{ 
float coef;

coef = .9003*init->radius*cos(posn->y - init->phi1);
pp->x = (posn->x - init->lon0)*coef;
pp->y = 1.4142*init->radius*sin(posn->y - init->phi1);
if (pp->x > (PI*coef)) {
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {
	pp->x += ((2*PI)*coef);
	return 1;
	}
return 0;
} 

int Ortho(Point *posn, ProjParam *init, Point *pp)
{
float cos_c;
float dl; 
dl = posn->x  - init->lon0;

pp->x = init->radius*cos(posn->y)*sin(dl); 
if ((posn->y != -PI) && (posn->y != PI))
	pp->y = init->radius*(cos(init->phi1)*sin(posn->y) - 
	sin(init->phi1)*cos(posn->y)*cos(dl));
else
	pp->y = init->radius*cos(posn->y)*cos(dl);
if (posn->y == PI)							/* conditionals for line removal */
	pp->y = - pp->y;
cos_c = sin(init->phi1)*sin(posn->y)+cos(init->phi1)*cos(posn->y)*cos(dl);
if (cos_c < 0)
	pp->pen = SKIP;
return 0;
} 


int Sinusoidal(Point *posn, ProjParam *init, Point *pp)
{
float coef;
float xofs;

coef = init->radius*cos(posn->y - init->phi1);
pp->x = (posn->x - init->lon0)*coef ; 
pp->y = init->radius*(posn->y - init->phi1);
if (pp->x > (PI*coef)) {			/* clipping conditonals for animation */
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {		/* conditionals for animation */
	pp->x += ((2*PI)*coef);
	return 1;
	}
return 0;
}


int Stereo(Point *posn, ProjParam *init, Point *pp)
{ 
float dl,k,r; 
float Len;
dl = posn->x - init->lon0;
r = init->radius*0.6;
k = 2/(1+sin(init->phi1)*sin(posn->y)+cos(init->phi1)*cos(posn->y)*cos(dl));
pp->x = r*k*cos(posn->y)*sin(dl);
pp->y = r*k*(cos(init->phi1)*sin(posn->y) - sin(init->phi1)*cos(posn->y)*cos(dl));
Len = sqrt((pp->x)*(pp->x) + (pp->y)*(pp->y));
if (Len > init->radius*1.2)
	pp->pen = SKIP;
return 0;
}

int None(Point *posn, ProjParam *init, Point *pp)
{ 
float dl; 
float Len;
float coef;
coef = init->radius;
dl = posn->x - init->lon0;
pp->x = coef*dl;
pp->y =  coef*(posn->y - init->phi1);
if (pp->x > (PI*coef)) {			/* clipping condtionals for animation */
	pp->x -= ((2*PI)*coef);
	return 1;
	}
if (pp->x < ((-(PI))*coef)) {
	pp->x += ((2*PI)*coef);
	return 1;
	}
return 0;
}

 /****************************************************/ 
 
 void DoFrame(PointList *framelist) {
 /*
 **  This function creates two frame lines 
 **   for the projections
 **   all except stereographic and orthographic
 */		
  float lat, lon;
 Point framept;
 framept.pencolour = NX_DKGRAY;
   for (lon = -180;lon <= 180;lon += 360) {
 	for (lat = -75;lat <= 75;lat += 5)  {
		if (lat == 75)
			framept.pen = UP;
		else
			framept.pen = DOWN;
		framept.y = lat *toRADS;
		framept.x = lon *toRADS;
		addToPointList(framelist ,&framept);
		}
	}
 }
 
 void  drawCircleFrame(float radius, PointList *pout) {
 /* 
 ** This function generates
 ** a framing circle
 ** around stereographic and
 ** the orthographic
 ** projections.
 */
 Point p;
 float  step, x;
 p.pencolour = NX_DKGRAY;
 step = radius/100.0;
 for (x = -radius;x <= radius;x += step) {	/* to top half of circle */
 	p.y = sqrt(radius*radius - x*x);
	p.x = x;
	p.pen = DOWN;
	addToPointList(pout,&p);
	}
 for (x = radius-step;x >= (-radius+step); x -= step) {  /* do bottom half */
	p.y = -(sqrt(radius*radius - x*x));
	p.x = x;
	p.pen = DOWN;
	addToPointList(pout,&p);
	}
p.y = 0.0;
p.x = -radius;
p.pen = UP;
addToPointList(pout,&p); 
 }
 
/****************************************************/

void DoGrid(PointList *gridlist) {
/*
** This function generates the graticules
** for the output view 
** for all the projections
** it increments at 15 degree intervals
*/
int lat, lon;
Point  gridpt ;

gridpt.pencolour = NX_LTGRAY;
gridpt.pen = DOWN;
/*  
** Compute the lines of latitude
*/

for (lat = -75;lat <= 75;lat += 15) { 
	for (lon = -180;lon <= 180; lon += 5)
		{ 
		if (lon == 180 )
			gridpt.pen = UP;
		else 
			gridpt.pen = DOWN;
		gridpt.y = lat *toRADS;
		gridpt.x = lon *toRADS;
		addToPointList(gridlist,&gridpt);
		}
	} 
/*  
** Now compute the Meridians
*/

for (lon =  -180;lon < 180; lon += 15) {
	for (lat = -75;lat <= 75;lat += 5 ) 
		{
		if (lat == 75)
			gridpt.pen = UP;
		else
			gridpt.pen = DOWN;
		gridpt.y = lat *toRADS;
		gridpt.x = lon *toRADS;
		addToPointList(gridlist,&gridpt);
		}
	} 
}

void ComputePoints(int (*proj)(Point *posn, ProjParam *init, Point *pp), ProjParam *init,PointList *inlist,PointList *outlist)
{
/* 
** This function computes the output
** points given the input list of  (lat,lon) pairs
** it  calls the appropriate map projection routine
** determines line clipping in the form of skipping
** unnecessary points (points that won't be drawn to output)
** It places the computed points in an outlist list of points
** that can then be plotted
*/
int i ;
int oldsplit,split;
Point pp, old;
Point *pt;
int a =1;
old.pen = UP;
oldsplit = 1;
for (i = gotoPointInList(inlist,0,&pt);(i);i=gotoNextPointInList(inlist,&pt))	
	{
	
	pp = *pt;
	split = (*proj)(pt,init,&pp);
	if ((old.pen == DOWN) && (pp.pen == SKIP)) 
		old.pen = UP;
	if (split  != oldsplit)
		old.pen = UP;
	if (a) 
		a = 0;
	else
		addToPointList(outlist,&old);
	old = pp;
	oldsplit = split;
	}
if (inlist->quantity) {
	pp.pen = UP;
	addToPointList(outlist,&pp);
	}
}

int convertPoints(PointList *pin, PointList *pout, int gridon, ProjParam *init)
{
/* This function is the externally called function
** It handles whether to compute and draw the 
** grid and frames and computes the output points
** by calliing ComputePoints with the appropriate 
** map projection.
*/
PointList grid, frame;		/* point list for the frame around the projection */
ProjParam frameparam;		/* frame drawing initialization paramaters */

frameparam.radius  = init->radius;	/* get the current radius */
frameparam.lon0 = 0.0;			/* fix the central meridian for frame computation */
frameparam.phi1 = init->phi1;	/* get the current central line of latitude */

init->lon0 = correct(init->lon0);	/* correct the offset for animation */
newPointList(&grid);			/* generate a new list for the grid */
newPointList(&frame);			/* generate a new list for the frame */
DoFrame(&frame);				/* compute the frame */
if (gridon)						
	DoGrid(&grid);			/* if want the grid displayed then compute the grid */

switch (init->proj)				/* select the appropriate projection to compute */
	{
	case CYLINDER: 
		ComputePoints(&Cylindrical,init,&grid,pout);
		ComputePoints(&Cylindrical,&frameparam,&frame,pout);
		ComputePoints(&Cylindrical,init,pin,pout);
		break;
	case ECKERT:  
		ComputePoints(&EckertIV,init,&grid,pout);
		ComputePoints(&EckertIV,&frameparam,&frame,pout);
		ComputePoints(&EckertIV,init,pin,pout);
		break;
	case MERCATOR: 
		ComputePoints(&Mercator,init,&grid,pout);
		ComputePoints(&Mercator,&frameparam,&frame,pout);
		ComputePoints(&Mercator,init,pin,pout);
		break;
	case MOLLWEIDE:  
		ComputePoints(&Mollweide,init,&grid,pout);
		ComputePoints(&Mollweide,&frameparam,&frame,pout);
		ComputePoints(&Mollweide,init,pin,pout);
		break;
	case ORTHO: 
		ComputePoints(&Ortho,init,&grid,pout);
		drawCircleFrame(init->radius,pout);
		ComputePoints(&Ortho,init,pin,pout); 
		break;
	case SINUSOIDAL: 
		ComputePoints(&Sinusoidal,init,&grid,pout);
		ComputePoints(&Sinusoidal,&frameparam,&frame,pout);
		ComputePoints(&Sinusoidal,init,pin, pout);
		break;
	case STEREO: 
		ComputePoints(&Stereo,init,&grid,pout);
		drawCircleFrame(init->radius*1.2, pout);
		ComputePoints(&Stereo,init,pin,pout);
		break;
	case NONE:
		ComputePoints(&None,init,&grid,pout);
		ComputePoints(&None,init,pin,pout);
		break;
	default: break;
	}
return 1;
}


These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.