/********************************************************************* ********************************************************************** * * * C O P Y R I G H T * * * * Copyright 1988,1989,1990 (C) by * * Purdue Research Foundation * * Purdue University * * West Lafayette, Indiana 47907 * * * * This software, in whole or in part, may be used and copied only * * with the written permission of the Dept. of Earth and Atmospheric * * Sciences via E. M. Agee, Purdue University, West Lafayette, * * Indiana, and with the inclusion of the above copyright notice. * * This software or any copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * ********************************************************************** ROUTINE: maptran.c PROGRAMMER: Dan Vietor PROGRAM TYPE: WXP_LIBRARY VERSION: 1.3 WXP VERSION: 4.8 DATE: 930925 COMPUTER: IBM RS/6000 running AIX 3.1 C Compiler IBM RT/PC running AIX 2.2.1 C Compiler IBM RT/PC running BSD 4.3 C Compiler IBM AT compatible running MSDOS 3.x using the Microsoft C 6.0 Compiler. SUN 3 and 4 running SUNOS 4.1 DEC VaxStation running VMS 5.3 and GKS Interprocess communications based on either ATT UNIX System V Message queues or BSD Sockets. Asynchronous data stream function interface based on either System V ioctl, BSD 4.3 ioctl or Blaise Asynch Manager for MSDOS 3.x. Graphics calls based on ANSI C language Graphical Kernel System binding (revision dated July 1988) DESCRIPTION: This subroutine calculates map projection variables. REVISIONS: DATE: INIT: See map.c for other revision information Version 1 910701 DEV Debugged satellite transformation 920520 DEV 1.1 Added new projections 930815 DEV 1.2 Added new projection parameters 930925 DEV 1.3 ****************************************************************************/ #include <stdio.h> #include <string.h> #include <math.h> #include <time.h> #include "wxp.h" static int map_projection = PROJ_PSTEREO; /* The map projection */ static float proj_lat; /* The projection base latitude */ static float proj_lon; /* The projection base longitude */ static float sat_rad = 421.61; static float sat_rad2 = 177754.9921; static float sat_rad4 = 3.159683722e10; static float sat2_earth2 = 173696.028; static float earth_rad = 63.71; static float sat_ratio = MISS; static float earth_ratio = MISS; static float tlat1 = 30; static float tlat2 = 60; static float cfactor = MISS; static float scale; /******************************************************************* MAPPROJ - This function sets the type of projection used in plots ********************************************************************/ int mapproj_str( proj ) char *proj; { int type; if( !strncmp( proj, "ll", 2 )) type = PROJ_LATLON; else if( !strncmp( proj, "ps", 2 )) type = PROJ_PSTEREO; else if( !strncmp( proj, "sat", 3 )) type = PROJ_SAT; else if( !strncmp( proj, "lc", 2 )) type = PROJ_LAMB; else if( !strncmp( proj, "me", 2 )) type = PROJ_MERC; else if( !strncmp( proj, "pix", 3 )) type = PROJ_PIXEL; else if( !strncmp( proj, "xy", 2 )) type = PROJ_XY; else if( !strcmp( proj, "xlogp" )) type = PROJ_XLOGP; else if( !strcmp( proj, "cat" )) type = PROJ_CAT; else if( !strcmp( proj, "therm" )) type = PROJ_STUVE; else if( !strcmp( proj, "hodo" )) type = PROJ_POLAR; else if( !strcmp( proj, "vert" )) type = PROJ_XLOGP; else if( !strcmp( proj, "miss" )) type = MISS; else sscanf( proj,"%d",&type ); return type; } /******************************************************************* MAPPROJ - This function sets the type of projection used in plots ********************************************************************/ void mapproj( proj ) int proj; { map_projection = proj; cfactor = MISS; sat_ratio = MISS; } /******************************************************************* MAPGETPROJ - This function gets the type of projection ********************************************************************/ int mapgetproj( ) { return map_projection; } /******************************************************************* MAPPROJCOORD - This function sets extra map projection coordinates. ********************************************************************/ void mapprojcoord( value ) float value[]; { if( map_projection == PROJ_LAMB ){ tlat1 = value[0]; tlat2 = value[1]; } } /******************************************************************* MAPCOORD - This function sets the map coordinates. ********************************************************************/ void mapcoord( rlat,rlon ) float rlat,rlon; { proj_lat = rlat; proj_lon = rlon; cfactor = MISS; } /******************************************************************* MAPUNTRAN - This function converts projection coordinates back into latitude and longitude. ********************************************************************/ int mapuntran( x,y,lat,lon ) float x,y; float *lat,*lon; { float rad,ang; /* Polar stereographic projection */ if( map_projection == PROJ_PSTEREO ){ rad = sqrt( x*x + y*y ); if( proj_lat >= 0 ) scale = 1; else scale = -1; ang = atan2( x,-scale*y )*RDC; *lat = scale*90 - 2*scale*atan(rad/(1.866*earth_rad))*RDC; *lon = ang+proj_lon; } /* Lat lon projection */ else if( map_projection == PROJ_LATLON ){ *lon = x + proj_lon; if( *lon > 180 ) *lon -= 360; else if( *lon < -180 ) *lon += 360; *lat = y; } /* Mercator */ else if( map_projection == PROJ_MERC ){ *lon = (x/(earth_rad*DRC)) + proj_lon; if( *lon > 180 ) *lon -= 360; else if( *lon < -180 ) *lon += 360; *lat = 90 - 2.*RDC*atan(1./exp(y/earth_rad)); } /* Lambert conformal */ else if( map_projection == PROJ_LAMB ){ if( cfactor == MISS ){ if( proj_lat >= 0 ) scale = 1; else scale = -1; if( tlat1 == tlat2 ) cfactor = cos(( 90 - scale*tlat1 )*DRC ); else cfactor = log( cos( tlat1*DRC )) - log( cos( tlat2*DRC ))/ (log( tan((45-tlat1/2)*DRC)) - log( tan((45-tlat2/2)*DRC))); } rad = sqrt( x*x + y*y ); ang = atan2( x,-scale*y )*RDC; *lat = scale*90 - scale*2*RDC*atan( pow( rad / (2*earth_rad), 1/cfactor )); *lon = ang/cfactor+proj_lon; } /* Satellite projection */ else if( map_projection == PROJ_SAT ){ if( sat_ratio == MISS ){ sat_ratio = sat_rad / earth_rad; earth_ratio = earth_rad / sat_rad; } rad = x*x + y*y + sat_rad*sat_rad; scale = sat_rad4 - rad*sat2_earth2; if( scale < 0 ){ *lat = MISS; *lon = MISS; return(0); } scale = (sat_rad2 - sqrt( scale )) / rad; x *= scale; y *= scale; *lat = asin( y/earth_rad ); *lon = asin( x/(cos(*lat)*earth_rad))*RDC + proj_lon; *lat *= RDC; } return(1); } /******************************************************************* MAPTRAN - This function converts latitude and longitude for a particular point into projection coordinates. ********************************************************************/ int maptran( lat,lon,x,y ) float lat,lon; float *x,*y; { float rad,ang; float factor; /* Polar stereographic projection */ if( map_projection == PROJ_PSTEREO ){ if( proj_lat >= 0 ){ if( lat < -45 ) lat = -45; rad = 1.866*earth_rad*tan( ( 90-lat )*DRC/2 ); } else { if( lat > 45 ) lat = 45; rad = 1.866*earth_rad*tan( ( 90+lat )*DRC/2 ); } ang = ( lon-proj_lon )*DRC; *x = rad*sin(ang); *y = rad*cos(ang); if( proj_lat >= 0 ) *y = -*y; } /* Lat lon projection */ else if( map_projection == PROJ_LATLON ){ #define OFFSET 180 *x = lon - proj_lon; if( *x > OFFSET ) *x -= 2*OFFSET; if( *x < -OFFSET ) *x += 2*OFFSET; *y = lat; #undef OFFSET } /* Mercator */ else if( map_projection == PROJ_MERC ){ #define OFFSET 180*earth_rad*DRC *x = earth_rad*( lon-proj_lon ) * DRC; if( *x > OFFSET ) *x -= 2*OFFSET; else if( *x < -OFFSET ) *x += 2*OFFSET; *y = earth_rad*log( 1./tan((45-lat/2)*DRC)); #undef OFFSET } /* Lambert conformal */ else if( map_projection == PROJ_LAMB ){ if( cfactor == MISS ){ if( proj_lat >= 0 ) scale = 1; else scale = -1; if( tlat1 == tlat2 ) cfactor = cos(( 90 - scale*tlat1 )*DRC ); else cfactor = log( cos( tlat1*DRC )) - log( cos( tlat2*DRC ))/ (log( tan((45-tlat1/2)*DRC)) - log( tan((45-tlat2/2)*DRC))); } factor = 2*earth_rad*pow(tan((45-scale*lat/2)*DRC),cfactor ); *x = factor*sin( cfactor*( lon-proj_lon )*DRC ); *y = -scale*factor*cos( cfactor*( lon-proj_lon )*DRC ); } /* Satellite projection */ else if( map_projection == PROJ_SAT ){ if( sat_ratio == MISS ){ sat_ratio = sat_rad / earth_rad; earth_ratio = earth_rad / sat_rad; } factor = cos(lat*DRC)*cos((lon-proj_lon)*DRC); if( factor < earth_ratio ){ *x = MISS; *y = MISS; return(0); } factor = sat_rad - earth_rad*factor; scale = sat_rad; *x = scale * earth_rad * sin((lon-proj_lon)*DRC) * cos(lat*DRC)/factor; *y = scale * earth_rad * sin(lat*DRC)/factor; } /* PIXEL projection */ else if( map_projection == PROJ_PIXEL ){ *x = lat; *y = -lon; } /* XY projection */ else if( map_projection == PROJ_XY || map_projection == PROJ_CAT ){ *x = lat; *y = lon; } /* XLOGP projection */ else if( map_projection == PROJ_XLOGP ){ *x = lat; *y = -log(lon); } return(1); } /******************************************************************* MAP_OFFSET - This routine offsets a point in a specific direction and distance on the earth and returns the point in projection space. ********************************************************************/ void map_offset( xi,yi,dir,rad,xf,yf ) float xi; /* The x location based on projection */ float yi; /* The y location based on projection */ float dir; /* The actual direction based on true north */ float rad; /* The actual distance in km */ float *xf; /* The x location based on projection */ float *yf; /* The y location based on projection */ { float lat,lon; float xoff,yoff; mapuntran( xi,yi,&lat,&lon ); xoff = rad*sin( dir*DRC ); yoff = rad*cos( dir*DRC ); lon += xoff/(111.195*cos(lat*DRC)); lat += yoff/111.195; maptran( lat,lon,xf,yf ); } /******************************************************************* MAP_DIR_ADJ - This routine adjusts the wind direction based on location and map projection. ********************************************************************/ float map_dir_adj( dir,x,y ) float dir; /* The actual direction based on true north */ float x; /* The x location based on projection */ float y; /* The y location based on projection */ { float lat,lon; float xoff,yoff; if( map_projection == PROJ_PSTEREO ){ if( x == 0 && y == 0 ){ if( proj_lat >= 0 ) dir = dir - proj_lon; else dir = dir + proj_lon; } else if( proj_lat >= 0 ) dir = dir - atan2( x,-y ) * RDC; else dir = dir + atan2( x,y ) * RDC; } else if( map_projection == PROJ_LAMB ){ if( cfactor == MISS ){ if( proj_lat >= 0 ) scale = 1; else scale = -1; if( tlat1 == tlat2 ) cfactor = cos(( 90 - scale*tlat1 )*DRC ); else cfactor = log( cos( tlat1*DRC )) - log( cos( tlat2*DRC ))/ (log( tan((45-scale*tlat1/2)*DRC)) - log( tan((45-scale*tlat2/2)*DRC))); } dir = dir - atan2( x,-scale*y ) * RDC; } else if( map_projection == PROJ_SAT ){ mapuntran( x,y,&lat,&lon ); xoff = sin( dir*DRC ); yoff = cos( dir*DRC ); lon += xoff/(111.195*cos(lat*DRC)); lat += yoff/111.195; maptran( lat,lon,&xoff,&yoff ); if( xoff == MISS || yoff == MISS ) dir = MISS; else dir = atan2(xoff-x,yoff-y)*RDC; } return dir; } /******************************************************************* MAP_UVDIR_ADJ - This routine adjusts the wind direction based on location and map projection. ********************************************************************/ float map_uvdir_adj( u,v,x,y ) float u,v; /* The actual direction based on true north */ float x; /* The x location based on projection */ float y; /* The y location based on projection */ { float dir; dir = 0; if( map_projection == PROJ_PSTEREO ){ if( x == 0 && y == 0 ){ if( proj_lat >= 0 ) dir = dir - proj_lon; else dir = dir + proj_lon; } else if( proj_lat >= 0 ) dir = dir - atan2( x,-y ) * RDC; else dir = dir + atan2( x,y ) * RDC; } return dir; } /******************************************************************* MAP_DIR - This routine adjusts the wind direction based on location and map projection. ********************************************************************/ float map_dir( x1,y1,x2,y2 ) float x1,y1; /* The first point */ float x2,y2; /* The second point */ { float dir; if( map_projection == PROJ_PSTEREO ){ dir = atan2(x2-x1,y2-y1)*RDC; if( proj_lat >= 0 ) dir = dir + atan2( x1,-y1 ) * RDC; else dir = dir - atan2( x1,y1 ) * RDC; } else dir = atan2(x2-x1,y2-y1)*RDC; return dir; } /******************************************************************* DOMAIN_INIT - This routine initializes the plot domain parameters. ********************************************************************/ void domain_init( domain ) DOM_params *domain; /* The domain */ { domain->proj = MISS; domain->lat[0] = MISS; domain->lat[1] = MISS; domain->lon[0] = MISS; domain->lon[1] = MISS; domain->dx = MISS; domain->dy = MISS; domain->nx = MISS; domain->ny = MISS; domain->param[0] = MISS; domain->param[1] = MISS; domain->param[2] = MISS; domain->param[3] = MISS; domain->param[4] = MISS; }