26 #include "mosaic_util.h"
29 #define HPI (0.5*M_PI)
30 #define TPI (2.0*M_PI)
31 #define TOLORENCE (1.e-6)
32 #define EPSLN8 (1.e-8)
33 #define EPSLN10 (1.e-10)
34 #define EPSLN15 (1.e-15)
35 #define EPSLN30 (1.e-30)
47 void error_handler(
const char *msg)
49 fprintf(
stderr,
"FATAL Error: %s\n", msg );
51 MPI_Abort(MPI_COMM_WORLD, -1);
72 int nearest_index(
double value,
const double *array,
int ia)
78 if (array[i] < array[i-1])
79 error_handler(
"nearest_index: array must be monotonically increasing");
81 if (value < array[0] )
83 else if ( value > array[ia-1])
89 while (i < ia && keep_going) {
91 if (value <= array[i]) {
93 if (array[i]-value > value-array[i-1]) index = i-1;
104 void tokenize(
const char *
const string,
const char *tokens,
unsigned int varlen,
105 unsigned int maxvar,
char * pstring,
unsigned int *
const nstr)
107 size_t i, j,
nvar, len, ntoken;
111 len = strlen(
string);
112 ntoken = strlen(tokens);
114 if(
string[0] == 0)error_handler(
"Error from tokenize: to-be-parsed string is empty");
116 for(i = 0; i < len; i ++){
117 if(
string[i] !=
' ' &&
string[i] !=
'\t'){
119 for(n=0; n<ntoken; n++) {
120 if(
string[i] == tokens[n] ) {
127 *(pstring + (
nvar++)*varlen + j) = 0;
129 if(
nvar >= maxvar) error_handler(
"Error from tokenize: number of variables exceeds limit");
133 *(pstring +
nvar*varlen + j++) =
string[i];
134 if(j >= varlen ) error_handler(
"error from tokenize: variable name length exceeds limit during tokenization");
138 *(pstring +
nvar*varlen + j) = 0;
148 double maxval_double(
int size,
const double *data)
154 for(n=1; n<size; n++){
155 if( data[n] > maxval ) maxval = data[n];
167 double minval_double(
int size,
const double *data)
173 for(n=1; n<size; n++){
174 if( data[n] < minval ) minval = data[n];
185 double avgval_double(
int size,
const double *data)
191 for(n=0; n<size; n++) avgval += data[n];
203 void latlon2xyz(
int size,
const double *lon,
const double *lat,
double *x,
double *y,
double *z)
207 for(n=0; n<size; n++) {
208 x[n] = cos(lat[n])*cos(lon[n]);
209 y[n] = cos(lat[n])*sin(lon[n]);
219 void xyz2latlon(
int np,
const double *x,
const double *y,
const double *z,
double *lon,
double *lat)
226 for(i=0; i<np; i++) {
230 dist = sqrt(xx*xx+yy*yy+zz*zz);
235 if ( fabs(xx)+fabs(yy) < EPSLN10 )
238 lon[i] = atan2(yy, xx);
241 if ( lon[i] < 0.) lon[i] = 2.*M_PI + lon[i];
250 double box_area(
double ll_lon,
double ll_lat,
double ur_lon,
double ur_lat)
252 double dx = ur_lon-ll_lon;
254 if(dx > M_PI) dx = dx - 2.0*M_PI;
255 if(dx < -M_PI) dx = dx + 2.0*M_PI;
257 return (dx*(sin(ur_lat)-sin(ll_lat))*RADIUS*RADIUS ) ;
269 double poly_area_dimensionless(
const double x[],
const double y[],
int n)
276 double dx = (x[ip]-x[i]);
282 if(dx > M_PI) dx = dx - 2.0*M_PI;
283 if(dx < -M_PI) dx = dx + 2.0*M_PI;
284 if (dx==0.0)
continue;
286 if ( fabs(lat1-lat2) < SMALL_VALUE)
287 area -= dx*sin(0.5*(lat1+lat2));
289 dy = 0.5*(lat1-lat2);
291 area -= dx*sin(0.5*(lat1+lat2))*dat;
295 return (-
area/(4*M_PI));
297 return (
area/(4*M_PI));
301 double poly_area(
const double x[],
const double y[],
int n)
308 double dx = (x[ip]-x[i]);
314 if(dx > M_PI) dx = dx - 2.0*M_PI;
315 if(dx < -M_PI) dx = dx + 2.0*M_PI;
316 if (dx==0.0)
continue;
318 if ( fabs(lat1-lat2) < SMALL_VALUE)
319 area -= dx*sin(0.5*(lat1+lat2));
321 dy = 0.5*(lat1-lat2);
323 area -= dx*sin(0.5*(lat1+lat2))*dat;
327 return -
area*RADIUS*RADIUS;
329 return area*RADIUS*RADIUS;
333 double poly_area_no_adjust(
const double x[],
const double y[],
int n)
340 double dx = (x[ip]-x[i]);
345 if (dx==0.0)
continue;
347 if ( fabs(lat1-lat2) < SMALL_VALUE)
348 area -= dx*sin(0.5*(lat1+lat2));
350 area += dx*(cos(lat1)-cos(lat2))/(lat1-lat2);
353 return area*RADIUS*RADIUS;
355 return area*RADIUS*RADIUS;
358 int delete_vtx(
double x[],
double y[],
int n,
int n_del)
360 for (;n_del<n-1;n_del++) {
361 x[n_del] = x[n_del+1];
362 y[n_del] = y[n_del+1];
368 int insert_vtx(
double x[],
double y[],
int n,
int n_ins,
double lon_in,
double lat_in)
372 for (i=n-1;i>=n_ins;i--) {
382 void v_print(
double x[],
double y[],
int n)
387 printf(
" %20g %20g\n", x[i], y[i]);
391 int fix_lon(
double x[],
double y[],
int n,
double tlon)
393 double x_sum, dx, dx_;
394 int i, nn = n, pole = 0;
396 for (i=0;i<nn;i++)
if (fabs(y[i])>=HPI-TOLORENCE) pole = 1;
398 printf(
"fixing pole cell\n");
404 for (i=0;i<nn;i++)
if (fabs(y[i])>=HPI-TOLORENCE) {
405 int im=(i+nn-1)%nn, ip=(i+1)%nn;
407 if (y[im]==y[i] && y[ip]==y[i]) {
408 nn = delete_vtx(x, y, nn, i);
410 }
else if (y[im]!=y[i] && y[ip]!=y[i]) {
411 nn = insert_vtx(x, y, nn, i, x[i], y[i]);
417 for (i=0;i<nn;i++)
if (fabs(y[i])>=HPI-TOLORENCE) {
418 int im=(i+nn-1)%nn, ip=(i+1)%nn;
437 if (dx_ < -M_PI) dx_ = dx_ + TPI;
438 else if (dx_ > M_PI) dx_ = dx_ - TPI;
439 x_sum += (x[i] = x[i-1] + dx_);
442 dx = (x_sum/nn)-tlon;
455 printf(
"area=%g\n", poly_area(x, y,nn));
470 double great_circle_distance(
double *p1,
double *p2)
477 beta = 2.*asin( sqrt( sin((p1[1]-p2[1])/2.)*sin((p1[1]-p2[1])/2.) +
478 cos(p1[1])*cos(p2[1])*(sin((p1[0]-p2[0])/2.)*sin((p1[0]-p2[0])/2.)) ) );
486 double great_circle_area(
int n,
const double *x,
const double *y,
const double *z) {
488 double pnt0[3], pnt1[3], pnt2[3];
493 for ( i=0; i<n; i++) {
498 pnt1[0] = x[(i+1)%n];
499 pnt1[1] = y[(i+1)%n];
500 pnt1[2] = z[(i+1)%n];
501 pnt2[0] = x[(i+2)%n];
502 pnt2[1] = y[(i+2)%n];
503 pnt2[2] = z[(i+2)%n];
506 sum += spherical_angle(pnt1, pnt2, pnt0);
509 area = (sum - (n-2.)*M_PI) * RADIUS* RADIUS;
523 double spherical_angle(
const double *v1,
const double *v2,
const double *v3)
526 long double px, py, pz, qx, qy, qz, ddd;
529 px = v1[1]*v2[2] - v1[2]*v2[1];
530 py = v1[2]*v2[0] - v1[0]*v2[2];
531 pz = v1[0]*v2[1] - v1[1]*v2[0];
533 qx = v1[1]*v3[2] - v1[2]*v3[1];
534 qy = v1[2]*v3[0] - v1[0]*v3[2];
535 qz = v1[0]*v3[1] - v1[1]*v3[0];
537 ddd = (px*px+py*py+pz*pz)*(qx*qx+qy*qy+qz*qz);
541 ddd = (px*qx+py*qy+pz*qz) / sqrtl(ddd);
542 if( fabsl(ddd-1) < EPSLN30 ) ddd = 1;
543 if( fabsl(ddd+1) < EPSLN30 ) ddd = -1;
544 if ( ddd>1. || ddd<-1. ) {
552 angle = ((double)acosl( ddd ));
564 double spherical_excess_area(
const double* p_ll,
const double* p_ul,
565 const double* p_lr,
const double* p_ur,
double radius)
567 double area, ang1, ang2, ang3, ang4;
568 double v1[3], v2[3], v3[3];
574 ang1 = spherical_angle(v1, v2, v3);
580 ang2 = spherical_angle(v1, v2, v3);
586 ang3 = spherical_angle(v1, v2, v3);
592 ang4 = spherical_angle(v1, v2, v3);
594 area = (ang1 + ang2 + ang3 + ang4 - 2.*M_PI) * radius* radius;
606 void vect_cross(
const double *p1,
const double *p2,
double *e )
609 e[0] = p1[1]*p2[2] - p1[2]*p2[1];
610 e[1] = p1[2]*p2[0] - p1[0]*p2[2];
611 e[2] = p1[0]*p2[1] - p1[1]*p2[0];
621 double dot(
const double *p1,
const double *p2)
624 return( p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2] );
629 double metric(
const double *p) {
630 return (sqrt(p[0]*p[0] + p[1]*p[1]+p[2]*p[2]) );
637 void normalize_vect(
double *e)
642 pdot = e[0]*e[0] + e[1] * e[1] + e[2] * e[2];
645 for(k=0; k<3; k++) e[k] /= pdot;
655 void unit_vect_latlon(
int size,
const double *lon,
const double *lat,
double *vlon,
double *vlat)
657 double sin_lon, cos_lon, sin_lat, cos_lat;
660 for(n=0; n<size; n++) {
661 sin_lon = sin(lon[n]);
662 cos_lon = cos(lon[n]);
663 sin_lat = sin(lat[n]);
664 cos_lat = cos(lat[n]);
666 vlon[3*n] = -sin_lon;
667 vlon[3*n+1] = cos_lon;
670 vlat[3*n] = -sin_lat*cos_lon;
671 vlat[3*n+1] = -sin_lat*sin_lon;
672 vlat[3*n+2] = cos_lat;
685 int intersect_tri_with_line(
const double *plane,
const double *l1,
const double *l2,
double *p,
688 long double M[3*3], inv_M[3*3];
693 const double *pnt0=plane;
694 const double *pnt1=plane+3;
695 const double *pnt2=plane+6;
700 M[0]=l1[0]-l2[0]; M[1]=pnt1[0]-pnt0[0]; M[2]=pnt2[0]-pnt0[0];
701 M[3]=l1[1]-l2[1]; M[4]=pnt1[1]-pnt0[1]; M[5]=pnt2[1]-pnt0[1];
702 M[6]=l1[2]-l2[2]; M[7]=pnt1[2]-pnt0[2]; M[8]=pnt2[2]-pnt0[2];
706 is_invert = invert_matrix_3x3(M,inv_M);
707 if (!is_invert)
return 0;
726 void mult(
long double m[],
long double v[],
long double out_v[]) {
728 out_v[0]=m[0]*v[0]+m[1]*v[1]+m[2]*v[2];
729 out_v[1]=m[3]*v[0]+m[4]*v[1]+m[5]*v[2];
730 out_v[2]=m[6]*v[0]+m[7]*v[1]+m[8]*v[2];
736 int invert_matrix_3x3(
long double m[],
long double m_inv[]) {
739 const long double det = m[0] * (m[4]*m[8] - m[5]*m[7])
740 -m[1] * (m[3]*m[8] - m[5]*m[6])
741 +m[2] * (m[3]*m[7] - m[4]*m[6]);
742 #ifdef test_invert_matrix_3x3
743 printf(
"det = %Lf\n", det);
745 if (fabsl(det) < EPSLN15 )
return 0;
747 const long double deti = 1.0/det;
749 m_inv[0] = (m[4]*m[8] - m[5]*m[7]) * deti;
750 m_inv[1] = (m[2]*m[7] - m[1]*m[8]) * deti;
751 m_inv[2] = (m[1]*m[5] - m[2]*m[4]) * deti;
753 m_inv[3] = (m[5]*m[6] - m[3]*m[8]) * deti;
754 m_inv[4] = (m[0]*m[8] - m[2]*m[6]) * deti;
755 m_inv[5] = (m[2]*m[3] - m[0]*m[5]) * deti;
757 m_inv[6] = (m[3]*m[7] - m[4]*m[6]) * deti;
758 m_inv[7] = (m[1]*m[6] - m[0]*m[7]) * deti;
759 m_inv[8] = (m[0]*m[4] - m[1]*m[3]) * deti;
765 #define MAXNODELIST 100
768 struct Node *nodeList=NULL;
771 void rewindList(
void)
776 if(!nodeList) nodeList = (
struct Node *)malloc(MAXNODELIST*
sizeof(
struct Node));
777 for(n=0; n<MAXNODELIST; n++) initNode(nodeList+n);
781 struct Node *getNext()
783 struct Node *temp=NULL;
787 nodeList = (
struct Node *)malloc(MAXNODELIST*
sizeof(
struct Node));
788 for(n=0; n<MAXNODELIST; n++) initNode(nodeList+n);
791 temp = nodeList+curListPos;
793 if(curListPos > MAXNODELIST) error_handler(
"getNext: curListPos >= MAXNODELIST");
799 void initNode(
struct Node *node)
813 void addEnd(
struct Node *list,
double x,
double y,
double z,
int intersect,
double u,
int inbound,
int inside)
816 struct Node *temp=NULL;
818 if(list == NULL) error_handler(
"addEnd: list is NULL");
820 if(list->initialized) {
825 if(samePoint(temp->x, temp->y, temp->z, x, y, z))
return;
833 temp->Next = getNext();
844 temp->intersect = intersect;
845 temp->inbound = inbound;
847 temp->isInside = inside;
852 int addIntersect(
struct Node *list,
double x,
double y,
double z,
int intersect,
double u1,
double u2,
int inbound,
853 int is1,
int ie1,
int is2,
int ie2)
856 double u1_cur, u2_cur;
858 struct Node *temp=NULL;
860 if(list == NULL) error_handler(
"addEnd: list is NULL");
876 if(list->initialized) {
879 if( temp->u == u1_cur && temp->subj_index == i1_cur)
return 0;
880 if( temp->u_clip == u2_cur && temp->clip_index == i2_cur)
return 0;
881 if( !temp->Next )
break;
886 temp->Next = getNext();
896 temp->intersect = intersect;
897 temp->inbound = inbound;
901 temp->subj_index = i1_cur;
902 temp->u_clip = u2_cur;
903 temp->clip_index = i2_cur;
909 int length(
struct Node *list)
911 struct Node *cur_ptr=NULL;
918 if(cur_ptr->initialized ==0)
break;
919 cur_ptr=cur_ptr->Next;
926 int samePoint(
double x1,
double y1,
double z1,
double x2,
double y2,
double z2)
928 if( fabs(x1-x2) > EPSLN10 || fabs(y1-y2) > EPSLN10 || fabs(z1-z2) > EPSLN10 )
936 int sameNode(
struct Node node1,
struct Node node2)
938 if( node1.x == node2.x && node1.y == node2.y && node1.z==node2.z )
945 void addNode(
struct Node *list,
struct Node inNode)
948 addEnd(list, inNode.x, inNode.y, inNode.z, inNode.intersect, inNode.u, inNode.inbound, inNode.isInside);
952 struct Node *getNode(
struct Node *list,
struct Node inNode)
954 struct Node *thisNode=NULL;
955 struct Node *temp=NULL;
959 if( sameNode( *temp, inNode ) ) {
970 struct Node *getNextNode(
struct Node *list)
975 void copyNode(
struct Node *node_out,
struct Node node_in)
978 node_out->x = node_in.x;
979 node_out->y = node_in.y;
980 node_out->z = node_in.z;
981 node_out->u = node_in.u;
982 node_out->intersect = node_in.intersect;
983 node_out->inbound = node_in.inbound;
984 node_out->Next = NULL;
985 node_out->initialized = node_in.initialized;
986 node_out->isInside = node_in.isInside;
989 void printNode(
struct Node *list,
char *str)
993 if(list == NULL) error_handler(
"printNode: list is NULL");
994 if(str) printf(
" %s \n", str);
997 if(temp->initialized ==0)
break;
998 printf(
" (x, y, z, interset, inbound, isInside) = (%19.15f,%19.15f,%19.15f,%d,%d,%d)\n",
999 temp->x, temp->y, temp->z, temp->intersect, temp->inbound, temp->isInside);
1005 int intersectInList(
struct Node *list,
double x,
double y,
double z)
1013 if( temp->x == x && temp->y == y && temp->z == z ) {
1019 if (!found) error_handler(
"intersectInList: point (x,y,z) is not found in the list");
1020 if( temp->intersect == 2 )
1032 void insertIntersect(
struct Node *list,
double x,
double y,
double z,
double u1,
double u2,
int inbound,
1033 double x2,
double y2,
double z2)
1035 struct Node *temp1=NULL, *temp2=NULL;
1043 if( temp1->x == x2 && temp1->y == y2 && temp1->z == z2 ) {
1049 if (!found) error_handler(
"inserAfter: point (x,y,z) is not found in the list");
1055 temp1 = temp1->Next;
1056 if(!temp1) temp1 = list;
1059 temp1->intersect = 2;
1060 temp1->isInside = 1;
1069 if(u2 != 0 && u2 != 1) {
1072 temp2 = temp1->Next;
1073 if(!temp2) temp2 = list;
1074 while(temp2->intersect) {
1076 if(!temp2) temp2 = list;
1079 temp2->isInside = 0;
1081 else if(inbound ==2) {
1082 temp1->isInside = 0;
1086 temp2 = temp1->Next;
1088 if( temp2->intersect == 1 ) {
1089 if( temp2->u > u_cur ) {
1096 temp2 = temp2->Next;
1105 temp->intersect = 1;
1106 temp->inbound = inbound;
1108 temp->initialized = 1;
1114 double gridArea(
struct Node *grid) {
1115 double x[20], y[20], z[20];
1116 struct Node *temp=NULL;
1130 area = great_circle_area(n, x, y, z);
1136 int isIntersect(
struct Node node) {
1138 return node.intersect;
1143 int getInbound(
struct Node node )
1145 return node.inbound;
1148 struct Node *getLast(
struct Node *list)
1154 while( temp1->Next ) {
1155 temp1 = temp1->Next;
1163 int getFirstInbound(
struct Node *list,
struct Node *nodeOut)
1165 struct Node *temp=NULL;
1170 if( temp->inbound == 2 ) {
1171 copyNode(nodeOut, *temp);
1180 void getCoordinate(
struct Node node,
double *x,
double *y,
double *z)
1190 void getCoordinates(
struct Node *node,
double *p)
1200 void setCoordinate(
struct Node *node,
double x,
double y,
double z)
1214 void setInbound(
struct Node *interList,
struct Node *list)
1217 struct Node *temp1=NULL, *temp=NULL;
1218 struct Node *temp1_prev=NULL, *temp1_next=NULL;
1219 int prev_is_inside, next_is_inside;
1223 if(length(interList) == 0)
return;
1228 if( !temp->inbound) {
1235 if(sameNode(*temp1, *temp)) {
1236 if(!temp1_prev) temp1_prev = getLast(list);
1237 temp1_next = temp1->Next;
1238 if(!temp1_next) temp1_next = list;
1242 temp1 = temp1->Next;
1244 if(!temp1_next) error_handler(
"Error from create_xgrid.c: temp is not in list1");
1245 if( temp1_prev->isInside == 0 && temp1_next->isInside == 1)
1254 int isInside(
struct Node *node) {
1256 if(node->isInside == -1) error_handler(
"Error from mosaic_util.c: node->isInside is not set");
1257 return(node->isInside);
1264 int insidePolygon(
struct Node *node,
struct Node *list)
1267 double pnt0[3], pnt1[3], pnt2[3];
1269 struct Node *p1=NULL, *p2=NULL;
1289 if( samePoint(pnt0[0], pnt0[1], pnt0[2], pnt1[0], pnt1[1], pnt1[2]) ){
1292 anglesum += spherical_angle(pnt0, pnt2, pnt1);
1300 if( fabs(anglesum - 2*M_PI) < EPSLN8 ){
1307 #ifdef debug_test_create_xgrid
1308 printf(
"anglesum-2PI is %19.15f, is_inside = %d\n", anglesum- 2*M_PI, is_inside);
1315 int inside_a_polygon(
double *lon1,
double *lat1,
int *npts,
double *lon2,
double *lat2)
1318 double x2[20], y2[20], z2[20];
1320 double min_x2, max_x2, min_y2, max_y2, min_z2, max_z2;
1323 struct Node *grid1=NULL, *grid2=NULL;
1329 max_x2 = maxval_double(*npts, x2);
1330 if(x1 >= max_x2+RANGE_CHECK_CRITERIA)
return 0;
1331 min_x2 = minval_double(*npts, x2);
1332 if(min_x2 >= x1+RANGE_CHECK_CRITERIA)
return 0;
1334 max_y2 = maxval_double(*npts, y2);
1335 if(y1 >= max_y2+RANGE_CHECK_CRITERIA)
return 0;
1336 min_y2 = minval_double(*npts, y2);
1337 if(min_y2 >= y1+RANGE_CHECK_CRITERIA)
return 0;
1339 max_z2 = maxval_double(*npts, z2);
1340 if(z1 >= max_z2+RANGE_CHECK_CRITERIA)
return 0;
1341 min_z2 = minval_double(*npts, z2);
1342 if(min_z2 >= z1+RANGE_CHECK_CRITERIA)
return 0;
1350 addEnd(grid1, x1, y1, z1, 0, 0, 0, -1);
1351 for(i=0; i<*npts; i++) addEnd(grid2, x2[i], y2[i], z2[i], 0, 0, 0, -1);
1353 isinside = insidePolygon(grid1, grid2);
1359 int inside_a_polygon_(
double *lon1,
double *lat1,
int *npts,
double *lon2,
double *lat2)
1364 isinside = inside_a_polygon(lon1, lat1, npts, lon2, lat2);
pure elemental type(point) function latlon2xyz(lat, lon)
Return the (x,y,z) position of a given (lat,lon) point.
real(r8_kind), dimension(:,:), allocatable area
area of each grid box
integer nvar
No description.
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.