FMS  2025.04
Flexible Modeling System
grid_utils.c
Go to the documentation of this file.
1 /***********************************************************************
2  * Apache License 2.0
3  *
4  * This file is part of the GFDL Flexible Modeling System (FMS).
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * FMS is distributed in the hope that it will be useful, but WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15  * PARTICULAR PURPOSE. See the License for the specific language
16  * governing permissions and limitations under the License.
17  ***********************************************************************/
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <math.h>
21 #include <string.h>
22 #include "grid_utils.h"
23 #include "tree_utils.h"
24 #include "constant.h"
25 
26 #ifdef use_libMPI
27 #include <mpi.h>
28 #endif
29 
30 /** \file
31  * \ingroup mosaic
32  * \brief Error handling and other general utilities for @ref mosaic_mod
33  */
34 
35 /***********************************************************
36  void error_handler(char *str)
37  error handler: will print out error message and then abort
38 ***********************************************************/
39 
40 void error_handler(const char *msg)
41 {
42  fprintf(stderr, "FATAL Error: %s\n", msg );
43 #ifdef use_libMPI
44  MPI_Abort(MPI_COMM_WORLD, -1);
45 #else
46  exit(1);
47 #endif
48 } /* error_handler */
49 
50 
51 /*******************************************************************************
52  double maxval_double(int size, double *data)
53  get the maximum value of double array
54 *******************************************************************************/
55 double maxval_double(int size, const double *data)
56 {
57  int n;
58  double maxval;
59 
60  maxval = data[0];
61  for(n=1; n<size; n++){
62  if( data[n] > maxval ) maxval = data[n];
63  }
64 
65  return maxval;
66 
67 } /* maxval_double */
68 
69 
70 /*******************************************************************************
71  double minval_double(int size, double *data)
72  get the minimum value of double array
73 *******************************************************************************/
74 double minval_double(int size, const double *data)
75 {
76  int n;
77  double minval;
78 
79  minval = data[0];
80  for(n=1; n<size; n++){
81  if( data[n] < minval ) minval = data[n];
82  }
83 
84  return minval;
85 
86 } /* minval_double */
87 
88 /*******************************************************************************
89  double avgval_double(int size, double *data)
90  get the average value of double array
91 *******************************************************************************/
92 double avgval_double(int size, const double *data)
93 {
94  int n;
95  double avgval;
96 
97  avgval = 0;
98  for(n=0; n<size; n++) avgval += data[n];
99  avgval /= size;
100 
101  return avgval;
102 
103 } /* avgval_double */
104 
105 
106 /*******************************************************************************
107  void latlon2xyz
108  Routine to map (lon, lat) to (x,y,z)
109 ******************************************************************************/
110 void latlon2xyz(int size, const double *lon, const double *lat, double *x, double *y, double *z)
111 {
112  int n;
113 
114  for(n=0; n<size; n++) {
115  x[n] = cos(lat[n])*cos(lon[n]);
116  y[n] = cos(lat[n])*sin(lon[n]);
117  z[n] = sin(lat[n]);
118  }
119 
120 } /* latlon2xyz */
121 
122 /*------------------------------------------------------------
123  void xyz2laton(np, p, xs, ys)
124  Transfer cartesian coordinates to spherical coordinates
125  ----------------------------------------------------------*/
126 void xyz2latlon( int np, const double *x, const double *y, const double *z, double *lon, double *lat)
127 {
128 
129  double xx, yy, zz;
130  double dist;
131  int i;
132 
133  for(i=0; i<np; i++) {
134  xx = x[i];
135  yy = y[i];
136  zz = z[i];
137  dist = sqrt(xx*xx+yy*yy+zz*zz);
138  xx /= dist;
139  yy /= dist;
140  zz /= dist;
141 
142  if ( fabs(xx)+fabs(yy) < EPSLN10 )
143  lon[i] = 0;
144  else
145  lon[i] = atan2(yy, xx);
146  lat[i] = asin(zz);
147 
148  if ( lon[i] < 0.) lon[i] = 2.*M_PI + lon[i];
149  }
150 
151 } /* xyz2latlon */
152 
153 int delete_vtx(double x[], double y[], int n, int n_del)
154 {
155  for (;n_del<n-1;n_del++) {
156  x[n_del] = x[n_del+1];
157  y[n_del] = y[n_del+1];
158  }
159 
160  return (n-1);
161 } /* delete_vtx */
162 
163 int insert_vtx(double x[], double y[], int n, int n_ins, double lon_in, double lat_in)
164 {
165  int i;
166 
167  for (i=n-1;i>=n_ins;i--) {
168  x[i+1] = x[i];
169  y[i+1] = y[i];
170  }
171 
172  x[n_ins] = lon_in;
173  y[n_ins] = lat_in;
174  return (n+1);
175 } /* insert_vtx */
176 
177 void v_print(double x[], double y[], int n)
178 {
179  int i;
180 
181  for (i=0;i<n;i++){
182  printf(" %20g %20g\n", x[i], y[i]);
183  }
184 } /* v_print */
185 
186 int fix_lon(double x[], double y[], int n, double tlon)
187 {
188  double x_sum, dx, dx_;
189  int i, nn = n, pole = 0;
190 
191  for (i=0;i<nn;i++) if (fabs(y[i])>=HPI-TOLERANCE) pole = 1;
192  if (0&&pole) {
193  printf("fixing pole cell\n");
194  v_print(x, y, nn);
195  printf("---------");
196  }
197 
198  /* all pole points must be paired */
199  for (i=0;i<nn;i++) if (fabs(y[i])>=HPI-TOLERANCE) {
200  int im=(i+nn-1)%nn, ip=(i+1)%nn;
201 
202  if (y[im]==y[i] && y[ip]==y[i]) {
203  nn = delete_vtx(x, y, nn, i);
204  i--;
205  } else if (y[im]!=y[i] && y[ip]!=y[i]) {
206  nn = insert_vtx(x, y, nn, i, x[i], y[i]);
207  i++;
208  }
209  }
210  /* first of pole pair has longitude of previous vertex */
211  /* second of pole pair has longitude of subsequent vertex */
212  for (i=0;i<nn;i++) if (fabs(y[i])>=HPI-TOLERANCE) {
213  int im=(i+nn-1)%nn, ip=(i+1)%nn;
214 
215  if (y[im]!=y[i]){
216  x[i] = x[im];
217  }
218  if (y[ip]!=y[i]){
219  x[i] = x[ip];
220  }
221  }
222 
223  if (nn){
224  x_sum = x[0];
225  }
226  else{
227  return(0);
228  }
229  for (i=1;i<nn;i++) {
230  dx_ = x[i]-x[i-1];
231 
232  if (dx_ < -M_PI) dx_ = dx_ + TPI;
233  else if (dx_ > M_PI) dx_ = dx_ - TPI;
234  x_sum += (x[i] = x[i-1] + dx_);
235  }
236 
237  dx = (x_sum/nn)-tlon;
238  if (dx < -M_PI){
239  for (i=0;i<nn;i++){
240  x[i] += TPI;
241  }
242  }
243  else if (dx > M_PI){
244  for (i=0;i<nn;i++){
245  x[i] -= TPI;
246  }
247  }
248 
249  if (0&&pole) {
250  printf("area=%g\n", poly_area(x, y,nn));
251  v_print(x, y, nn);
252  printf("---------");
253  }
254 
255  return (nn);
256 } /* fix_lon */
257 
258 
259 /*------------------------------------------------------------------------------
260  double great_circle_distance()
261  computes distance between two points along a great circle
262  (the shortest distance between 2 points on a sphere)
263  returned in units of meter
264  ----------------------------------------------------------------------------*/
265 double great_circle_distance(double *p1, double *p2)
266 {
267  double dist, beta;
268 
269  /* This algorithm is not accurate for small distance
270  dist = RADIUS*ACOS(SIN(p1[1])*SIN(p2[1]) + COS(p1[1])*COS(p2[1])*COS(p1[0]-p2[0]));
271  */
272  beta = 2.*asin( sqrt( sin((p1[1]-p2[1])/2.)*sin((p1[1]-p2[1])/2.) +
273  cos(p1[1])*cos(p2[1])*(sin((p1[0]-p2[0])/2.)*sin((p1[0]-p2[0])/2.)) ) );
274  dist = RADIUS*beta;
275  return dist;
276 
277 } /* great_circle_distance */
278 
279 /*------------------------------------------------------------------------------
280  double spherical_angle(const double *p1, const double *p2, const double *p3)
281  p3
282  /
283  /
284  p1 ---> angle
285  \
286  \
287  p2
288  -----------------------------------------------------------------------------*/
289 double spherical_angle(const double *v1, const double *v2, const double *v3)
290 {
291  double angle;
292  long double px, py, pz, qx, qy, qz, ddd;
293 
294  /* vector product between v1 and v2 */
295  px = v1[1]*v2[2] - v1[2]*v2[1];
296  py = v1[2]*v2[0] - v1[0]*v2[2];
297  pz = v1[0]*v2[1] - v1[1]*v2[0];
298  /* vector product between v1 and v3 */
299  qx = v1[1]*v3[2] - v1[2]*v3[1];
300  qy = v1[2]*v3[0] - v1[0]*v3[2];
301  qz = v1[0]*v3[1] - v1[1]*v3[0];
302 
303  ddd = (px*px+py*py+pz*pz)*(qx*qx+qy*qy+qz*qz);
304  if ( ddd <= 0.0 )
305  angle = 0. ;
306  else {
307  ddd = (px*qx+py*qy+pz*qz) / sqrtl(ddd);
308  if( fabsl(ddd-1) < EPSLN30 ) ddd = 1;
309  if( fabsl(ddd+1) < EPSLN30 ) ddd = -1;
310  if ( ddd>1. || ddd<-1. ) {
311  /*FIX (lmh) to correctly handle co-linear points (angle near pi or 0) */
312  if (ddd < 0.)
313  angle = M_PI;
314  else
315  angle = 0.;
316  }
317  else
318  angle = ((double)acosl( ddd ));
319  }
320 
321  return angle;
322 } /* spherical_angle */
323 
324 
325 /*----------------------------------------------------------------------
326  void vect_cross(e, p1, p2)
327  Perform cross products of 3D vectors: e = P1 X P2
328  -------------------------------------------------------------------*/
329 
330 void vect_cross(const double *p1, const double *p2, double *e )
331 {
332 
333  e[0] = p1[1]*p2[2] - p1[2]*p2[1];
334  e[1] = p1[2]*p2[0] - p1[0]*p2[2];
335  e[2] = p1[0]*p2[1] - p1[1]*p2[0];
336 
337 } /* vect_cross */
338 
339 
340 /*----------------------------------------------------------------------
341  double* vect_cross(p1, p2)
342  return cross products of 3D vectors: = P1 X P2
343  -------------------------------------------------------------------*/
344 
345 double dot(const double *p1, const double *p2)
346 {
347 
348  return( p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2] );
349 
350 }
351 
352 
353 double metric(const double *p) {
354  return (sqrt(p[0]*p[0] + p[1]*p[1]+p[2]*p[2]) );
355 }
356 
357 void normalize_vect(double *e)
358 {
359  double pdot;
360  int k;
361 
362  pdot = e[0]*e[0] + e[1] * e[1] + e[2] * e[2];
363  pdot = sqrt( pdot );
364 
365  for(k=0; k<3; k++) e[k] /= pdot;
366 }
367 
368 
369 /*------------------------------------------------------------------
370  void unit_vect_latlon(int size, lon, lat, vlon, vlat)
371  calculate unit vector for latlon in cartesian coordinates
372  ---------------------------------------------------------------------*/
373 void unit_vect_latlon(int size, const double *lon, const double *lat, double *vlon, double *vlat)
374 {
375  double sin_lon, cos_lon, sin_lat, cos_lat;
376  int n;
377 
378  for(n=0; n<size; n++) {
379  sin_lon = sin(lon[n]);
380  cos_lon = cos(lon[n]);
381  sin_lat = sin(lat[n]);
382  cos_lat = cos(lat[n]);
383 
384  vlon[3*n] = -sin_lon;
385  vlon[3*n+1] = cos_lon;
386  vlon[3*n+2] = 0.;
387 
388  vlat[3*n] = -sin_lat*cos_lon;
389  vlat[3*n+1] = -sin_lat*sin_lon;
390  vlat[3*n+2] = cos_lat;
391  }
392 } /* unit_vect_latlon */
393 
394 
395 /* Intersect a line and a plane
396  Intersects between the plane ( three points ) (entries in counterclockwise order)
397  and the line determined by the endpoints l1 and l2 (t=0.0 at l1 and t=1.0 at l2)
398  returns true if the two intersect and the output variables are valid
399  outputs p containing the coordinates in the tri and t the coordinate in the line
400  of the intersection.
401  NOTE: the intersection doesn't have to be inside the tri or line for this to return true
402 */
403 int intersect_tri_with_line(const double *plane, const double *l1, const double *l2, double *p,
404  double *t) {
405 
406  long double M[3*3], inv_M[3*3];
407  long double V[3];
408  long double X[3];
409  int is_invert=0;
410 
411  const double *pnt0=plane;
412  const double *pnt1=plane+3;
413  const double *pnt2=plane+6;
414 
415  /* To do intersection just solve the set of linear equations for both
416  Setup M
417  */
418  M[0]=l1[0]-l2[0]; M[1]=pnt1[0]-pnt0[0]; M[2]=pnt2[0]-pnt0[0];
419  M[3]=l1[1]-l2[1]; M[4]=pnt1[1]-pnt0[1]; M[5]=pnt2[1]-pnt0[1];
420  M[6]=l1[2]-l2[2]; M[7]=pnt1[2]-pnt0[2]; M[8]=pnt2[2]-pnt0[2];
421 
422 
423  /* Invert M */
424  is_invert = invert_matrix_3x3(M,inv_M);
425  if (!is_invert) return 0;
426 
427  /* Set variable holding vector */
428  V[0]=l1[0]-pnt0[0];
429  V[1]=l1[1]-pnt0[1];
430  V[2]=l1[2]-pnt0[2];
431 
432  /* Calculate solution */
433  mult(inv_M, V, X);
434 
435  /* Get answer out */
436  *t=((double)X[0]);
437  p[0]=((double)X[1]);
438  p[1]=((double)X[2]);
439 
440  return 1;
441 }
442 
443 
444 void mult(long double m[], long double v[], long double out_v[]) {
445 
446  out_v[0]=m[0]*v[0]+m[1]*v[1]+m[2]*v[2];
447  out_v[1]=m[3]*v[0]+m[4]*v[1]+m[5]*v[2];
448  out_v[2]=m[6]*v[0]+m[7]*v[1]+m[8]*v[2];
449 
450 }
451 
452 
453 /* returns 1 if matrix is inverted, 0 otherwise */
454 int invert_matrix_3x3(long double m[], long double m_inv[]) {
455 
456 
457  const long double det = m[0] * (m[4]*m[8] - m[5]*m[7])
458  -m[1] * (m[3]*m[8] - m[5]*m[6])
459  +m[2] * (m[3]*m[7] - m[4]*m[6]);
460  if (fabsl(det) < EPSLN15 ) return 0;
461 
462  const long double deti = 1.0/det;
463 
464  m_inv[0] = (m[4]*m[8] - m[5]*m[7]) * deti;
465  m_inv[1] = (m[2]*m[7] - m[1]*m[8]) * deti;
466  m_inv[2] = (m[1]*m[5] - m[2]*m[4]) * deti;
467 
468  m_inv[3] = (m[5]*m[6] - m[3]*m[8]) * deti;
469  m_inv[4] = (m[0]*m[8] - m[2]*m[6]) * deti;
470  m_inv[5] = (m[2]*m[3] - m[0]*m[5]) * deti;
471 
472  m_inv[6] = (m[3]*m[7] - m[4]*m[6]) * deti;
473  m_inv[7] = (m[1]*m[6] - m[0]*m[7]) * deti;
474  m_inv[8] = (m[0]*m[4] - m[1]*m[3]) * deti;
475 
476  return 1;
477 }
478 
479 
480 int inside_a_polygon(double *lon1, double *lat1, int *npts, double *lon2, double *lat2)
481 {
482 
483  double x2[20], y2[20], z2[20];
484  double x1, y1, z1;
485  double min_x2, max_x2, min_y2, max_y2, min_z2, max_z2;
486  int isinside, i;
487 
488  struct Node *grid1=NULL, *grid2=NULL;
489 
490  /* first convert to cartesian grid */
491  latlon2xyz(*npts, lon2, lat2, x2, y2, z2);
492  latlon2xyz(1, lon1, lat1, &x1, &y1, &z1);
493 
494  max_x2 = maxval_double(*npts, x2);
495  if(x1 >= max_x2+RANGE_CHECK_CRITERIA) return 0;
496  min_x2 = minval_double(*npts, x2);
497  if(min_x2 >= x1+RANGE_CHECK_CRITERIA) return 0;
498 
499  max_y2 = maxval_double(*npts, y2);
500  if(y1 >= max_y2+RANGE_CHECK_CRITERIA) return 0;
501  min_y2 = minval_double(*npts, y2);
502  if(min_y2 >= y1+RANGE_CHECK_CRITERIA) return 0;
503 
504  max_z2 = maxval_double(*npts, z2);
505  if(z1 >= max_z2+RANGE_CHECK_CRITERIA) return 0;
506  min_z2 = minval_double(*npts, z2);
507  if(min_z2 >= z1+RANGE_CHECK_CRITERIA) return 0;
508 
509 
510  /* add x2,y2,z2 to a Node */
511  rewindList();
512  grid1 = getNext();
513  grid2 = getNext();
514 
515  addEnd(grid1, x1, y1, z1, 0, 0, 0, -1);
516  for(i=0; i<*npts; i++) addEnd(grid2, x2[i], y2[i], z2[i], 0, 0, 0, -1);
517 
518  isinside = insidePolygon(grid1, grid2);
519 
520  return isinside;
521 
522 }
523 
524 int inside_a_polygon_(double *lon1, double *lat1, int *npts, double *lon2, double *lat2)
525 {
526 
527  int isinside;
528 
529  isinside = inside_a_polygon(lon1, lat1, npts, lon2, lat2);
530 
531  return isinside;
532 
533 }
534 
535 double get_global_area(void)
536 {
537  double garea;
538  garea = 4*M_PI*RADIUS*RADIUS;
539 
540  return garea;
541 }
542 
543 double get_global_area_(void)
544 {
545  double garea;
546  garea = 4*M_PI*RADIUS*RADIUS;
547 
548  return garea;
549 }
550 
551 double poly_area(const double x[], const double y[], int n)
552 {
553  double area = 0.0;
554  int i;
555 
556  for (i=0;i<n;i++) {
557  int ip = (i+1) % n;
558  double dx = (x[ip]-x[i]);
559  double lat1, lat2;
560  double dy, dat;
561 
562  lat1 = y[ip];
563  lat2 = y[i];
564  if(dx > M_PI) dx = dx - 2.0*M_PI;
565  if(dx < -M_PI) dx = dx + 2.0*M_PI;
566  if (dx==0.0) continue;
567 
568  if ( fabs(lat1-lat2) < SMALL_VALUE) /* cheap area calculation along latitude */
569  area -= dx*sin(0.5*(lat1+lat2));
570  else {
571  dy = 0.5*(lat1-lat2);
572  dat = sin(dy)/dy;
573  area -= dx*sin(0.5*(lat1+lat2))*dat;
574  }
575  }
576  if(area < 0)
577  return -area*RADIUS*RADIUS;
578  else
579  return area*RADIUS*RADIUS;
580 
581 } /* poly_area */
582 
583 double poly_area_no_adjust(const double x[], const double y[], int n)
584 {
585  double area = 0.0;
586  int i;
587 
588  for (i=0;i<n;i++) {
589  int ip = (i+1) % n;
590  double dx = (x[ip]-x[i]);
591  double lat1, lat2;
592 
593  lat1 = y[ip];
594  lat2 = y[i];
595  if (dx==0.0) continue;
596 
597  if ( fabs(lat1-lat2) < SMALL_VALUE) /* cheap area calculation along latitude */
598  area -= dx*sin(0.5*(lat1+lat2));
599  else
600  area += dx*(cos(lat1)-cos(lat2))/(lat1-lat2);
601  }
602  if(area < 0)
603  return area*RADIUS*RADIUS;
604  else
605  return area*RADIUS*RADIUS;
606 } /* poly_area_no_adjust */
607 
608 /*------------------------------------------------------------------------------
609  double poly_area(const x[], const y[], int n)
610  obtains area of input polygon by line integrating -sin(lat)d(lon)
611  Vertex coordinates must be in degrees.
612  Vertices must be listed counter-clockwise around polygon.
613  grid is in radians.
614  ----------------------------------------------------------------------------*/
615 double poly_area_dimensionless(const double x[], const double y[], int n)
616 {
617  double area = 0.0;
618  int i;
619 
620  for (i=0;i<n;i++) {
621  int ip = (i+1) % n;
622  double dx = (x[ip]-x[i]);
623  double lat1, lat2;
624  double dy, dat;
625 
626  lat1 = y[ip];
627  lat2 = y[i];
628  if(dx > M_PI) dx = dx - 2.0*M_PI;
629  if(dx < -M_PI) dx = dx + 2.0*M_PI;
630  if (dx==0.0) continue;
631 
632  if ( fabs(lat1-lat2) < SMALL_VALUE) /* cheap area calculation along latitude */
633  area -= dx*sin(0.5*(lat1+lat2));
634  else {
635  dy = 0.5*(lat1-lat2);
636  dat = sin(dy)/dy;
637  area -= dx*sin(0.5*(lat1+lat2))*dat;
638  }
639  }
640  if(area < 0)
641  return (-area/(4*M_PI));
642  else
643  return (area/(4*M_PI));
644 
645 } /* poly_area */
646 
647 /* Compute the great circle area of a polygon on a sphere */
648 double great_circle_area(int n, const double *x, const double *y, const double *z) {
649  int i;
650  double pnt0[3], pnt1[3], pnt2[3];
651  double sum, area;
652 
653  /* sum angles around polygon */
654  sum=0.0;
655  for ( i=0; i<n; i++) {
656  /* points that make up a side of polygon */
657  pnt0[0] = x[i];
658  pnt0[1] = y[i];
659  pnt0[2] = z[i];
660  pnt1[0] = x[(i+1)%n];
661  pnt1[1] = y[(i+1)%n];
662  pnt1[2] = z[(i+1)%n];
663  pnt2[0] = x[(i+2)%n];
664  pnt2[1] = y[(i+2)%n];
665  pnt2[2] = z[(i+2)%n];
666 
667  /* compute angle for pnt1 */
668  sum += spherical_angle(pnt1, pnt2, pnt0);
669 
670  }
671  area = (sum - (n-2.)*M_PI) * RADIUS* RADIUS;
672  return area;
673 }
674 
675 /*------------------------------------------------------------------------------
676  double spherical_excess_area(p_lL, p_uL, p_lR, p_uR)
677  get the surface area of a cell defined as a quadrilateral
678  on the sphere. Area is computed as the spherical excess
679  [area units are m^2]
680  ----------------------------------------------------------------------------*/
681 double spherical_excess_area(const double* p_ll, const double* p_ul,
682  const double* p_lr, const double* p_ur, double radius)
683 {
684  double area, ang1, ang2, ang3, ang4;
685  double v1[3], v2[3], v3[3];
686 
687  /* S-W: 1 */
688  latlon2xyz(1, p_ll, p_ll+1, v1, v1+1, v1+2);
689  latlon2xyz(1, p_lr, p_lr+1, v2, v2+1, v2+2);
690  latlon2xyz(1, p_ul, p_ul+1, v3, v3+1, v3+2);
691  ang1 = spherical_angle(v1, v2, v3);
692 
693  /* S-E: 2 */
694  latlon2xyz(1, p_lr, p_lr+1, v1, v1+1, v1+2);
695  latlon2xyz(1, p_ur, p_ur+1, v2, v2+1, v2+2);
696  latlon2xyz(1, p_ll, p_ll+1, v3, v3+1, v3+2);
697  ang2 = spherical_angle(v1, v2, v3);
698 
699  /* N-E: 3 */
700  latlon2xyz(1, p_ur, p_ur+1, v1, v1+1, v1+2);
701  latlon2xyz(1, p_ul, p_ul+1, v2, v2+1, v2+2);
702  latlon2xyz(1, p_lr, p_lr+1, v3, v3+1, v3+2);
703  ang3 = spherical_angle(v1, v2, v3);
704 
705  /* N-W: 4 */
706  latlon2xyz(1, p_ul, p_ul+1, v1, v1+1, v1+2);
707  latlon2xyz(1, p_ur, p_ur+1, v2, v2+1, v2+2);
708  latlon2xyz(1, p_ll, p_ll+1, v3, v3+1, v3+2);
709  ang4 = spherical_angle(v1, v2, v3);
710 
711  area = (ang1 + ang2 + ang3 + ang4 - 2.*M_PI) * radius* radius;
712 
713  return area;
714 
715 } /* spherical_excess_area */
716 
717 /*******************************************************************************
718 void get_grid_area(const int *nlon, const int *nlat, const double *lon, const double *lat, const double *area)
719  return the grid area.
720 *******************************************************************************/
721 void get_grid_area_(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
722 {
723  get_grid_area(nlon, nlat, lon, lat, area);
724 }
725 
726 void get_grid_area(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
727 {
728  int nx, ny, nxp, i, j, n_in;
729  double x_in[20], y_in[20];
730 
731  nx = *nlon;
732  ny = *nlat;
733  nxp = nx + 1;
734 
735  for(j=0; j<ny; j++) for(i=0; i < nx; i++) {
736  x_in[0] = lon[j*nxp+i];
737  x_in[1] = lon[j*nxp+i+1];
738  x_in[2] = lon[(j+1)*nxp+i+1];
739  x_in[3] = lon[(j+1)*nxp+i];
740  y_in[0] = lat[j*nxp+i];
741  y_in[1] = lat[j*nxp+i+1];
742  y_in[2] = lat[(j+1)*nxp+i+1];
743  y_in[3] = lat[(j+1)*nxp+i];
744  n_in = fix_lon(x_in, y_in, 4, M_PI);
745  area[j*nx+i] = poly_area(x_in, y_in, n_in);
746  }
747 
748 } /* get_grid_area */
749 
750 
751 /*******************************************************************************
752 void get_grid_area_ug(const int *npts, const double *lon, const double *lat, const double *area)
753  return the grid area.
754 *******************************************************************************/
755 void get_grid_area_ug_(const int *npts, const double *lon, const double *lat, double *area)
756 {
757  get_grid_area_ug(npts, lon, lat, area);
758 }
759 
760 void get_grid_area_ug(const int *npts, const double *lon, const double *lat, double *area)
761 {
762  int nl, l, n_in, nv;
763  double x_in[20], y_in[20];
764 
765  nl = *npts;
766  nv = 4;
767 
768  for(l=0; l<nl; l++) {
769  x_in[0] = lon[l*nv];
770  x_in[1] = lon[l*nv+1];
771  x_in[2] = lon[l*nv+2];
772  x_in[3] = lon[l*nv+3];
773  y_in[0] = lat[l*nv];
774  y_in[1] = lat[l*nv+1];
775  y_in[2] = lat[l*nv+2];
776  y_in[3] = lat[l*nv+3];
777  n_in = fix_lon(x_in, y_in, nv, M_PI);
778  area[l] = poly_area(x_in, y_in, n_in);
779  }
780 
781 } /* get_grid_area_ug */
782 
783 
784 void get_grid_great_circle_area_(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
785 {
786  get_grid_great_circle_area(nlon, nlat, lon, lat, area);
787 
788 }
789 
790 void get_grid_great_circle_area(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
791 {
792  int nx, ny, nxp, nyp, i, j;
793  int n0, n1, n2, n3;
794  struct Node *grid=NULL;
795  double *x=NULL, *y=NULL, *z=NULL;
796 
797 
798  nx = *nlon;
799  ny = *nlat;
800  nxp = nx + 1;
801  nyp = ny + 1;
802 
803  x = (double *)malloc(nxp*nyp*sizeof(double));
804  y = (double *)malloc(nxp*nyp*sizeof(double));
805  z = (double *)malloc(nxp*nyp*sizeof(double));
806 
807  latlon2xyz(nxp*nyp, lon, lat, x, y, z);
808 
809  for(j=0; j<ny; j++) for(i=0; i < nx; i++) {
810  /* clockwise */
811  n0 = j*nxp+i;
812  n1 = (j+1)*nxp+i;
813  n2 = (j+1)*nxp+i+1;
814  n3 = j*nxp+i+1;
815  rewindList();
816  grid = getNext();
817  addEnd(grid, x[n0], y[n0], z[n0], 0, 0, 0, -1);
818  addEnd(grid, x[n1], y[n1], z[n1], 0, 0, 0, -1);
819  addEnd(grid, x[n2], y[n2], z[n2], 0, 0, 0, -1);
820  addEnd(grid, x[n3], y[n3], z[n3], 0, 0, 0, -1);
821  area[j*nx+i] = gridArea(grid);
822  }
823 
824  free(x);
825  free(y);
826  free(z);
827 
828 } /* get_grid_great_circle_area */
829 
830 void get_grid_great_circle_area_ug_(const int *npts, const double *lon, const double *lat, double *area)
831 {
832  get_grid_great_circle_area_ug(npts, lon, lat, area);
833 
834 }
835 
836 void get_grid_great_circle_area_ug(const int *npts, const double *lon, const double *lat, double *area)
837 {
838  int l, nl, nv;
839  int n0, n1, n2, n3;
840  struct Node *grid=NULL;
841  double *x=NULL, *y=NULL, *z=NULL;
842 
843  nl = *npts;
844  nv = 4;
845 
846  x = (double *)malloc(nl*nv*sizeof(double));
847  y = (double *)malloc(nl*nv*sizeof(double));
848  z = (double *)malloc(nl*nv*sizeof(double));
849 
850  latlon2xyz(nl*nv, lon, lat, x, y, z);
851 
852  for(l=0; l<nv; l++) {
853  /* clockwise */
854  n0 = l*nv;
855  n1 = l*nv+1;
856  n2 = l*nv+2;
857  n3 = l*nv+3;
858  rewindList();
859  grid = getNext();
860  addEnd(grid, x[n0], y[n0], z[n0], 0, 0, 0, -1);
861  addEnd(grid, x[n1], y[n1], z[n1], 0, 0, 0, -1);
862  addEnd(grid, x[n2], y[n2], z[n2], 0, 0, 0, -1);
863  addEnd(grid, x[n3], y[n3], z[n3], 0, 0, 0, -1);
864  area[l] = gridArea(grid);
865  }
866 
867  free(x);
868  free(y);
869  free(z);
870 
871 } /* get_grid_great_circle_area_ug */
872 
873 void get_grid_area_dimensionless(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
874 {
875  int nx, ny, nxp, i, j, n_in;
876  double x_in[20], y_in[20];
877 
878  nx = *nlon;
879  ny = *nlat;
880  nxp = nx + 1;
881 
882  for(j=0; j<ny; j++) for(i=0; i < nx; i++) {
883  x_in[0] = lon[j*nxp+i];
884  x_in[1] = lon[j*nxp+i+1];
885  x_in[2] = lon[(j+1)*nxp+i+1];
886  x_in[3] = lon[(j+1)*nxp+i];
887  y_in[0] = lat[j*nxp+i];
888  y_in[1] = lat[j*nxp+i+1];
889  y_in[2] = lat[(j+1)*nxp+i+1];
890  y_in[3] = lat[(j+1)*nxp+i];
891  n_in = fix_lon(x_in, y_in, 4, M_PI);
892  area[j*nx+i] = poly_area_dimensionless(x_in, y_in, n_in);
893  }
894 
895 } /* get_grid_area */
896 
897 
898 
899 void get_grid_area_no_adjust(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area)
900 {
901  int nx, ny, nxp, i, j, n_in;
902  double x_in[20], y_in[20];
903 
904  nx = *nlon;
905  ny = *nlat;
906  nxp = nx + 1;
907 
908  for(j=0; j<ny; j++) for(i=0; i < nx; i++) {
909  x_in[0] = lon[j*nxp+i];
910  x_in[1] = lon[j*nxp+i+1];
911  x_in[2] = lon[(j+1)*nxp+i+1];
912  x_in[3] = lon[(j+1)*nxp+i];
913  y_in[0] = lat[j*nxp+i];
914  y_in[1] = lat[j*nxp+i+1];
915  y_in[2] = lat[(j+1)*nxp+i+1];
916  y_in[3] = lat[(j+1)*nxp+i];
917  n_in = 4;
918  area[j*nx+i] = poly_area_no_adjust(x_in, y_in, n_in);
919  }
920 
921 } /* get_grid_area_no_adjust */
922 
923 
924 /*******************************************************************************
925  Sutherland-Hodgeman algorithm sequentially clips parts outside 4 boundaries
926 *******************************************************************************/
927 
928 int clip(const double lon_in[], const double lat_in[], int n_in, double ll_lon, double ll_lat,
929  double ur_lon, double ur_lat, double lon_out[], double lat_out[])
930 {
931  double x_tmp[MV], y_tmp[MV], x_last, y_last;
932  int i_in, i_out, n_out, inside_last, inside;
933 
934  /* clip polygon with LEFT boundary - clip V_IN to V_TMP */
935  x_last = lon_in[n_in-1];
936  y_last = lat_in[n_in-1];
937  inside_last = (x_last >= ll_lon);
938  for (i_in=0,i_out=0;i_in<n_in;i_in++) {
939 
940  /* if crossing LEFT boundary - output intersection */
941  if ((inside=(lon_in[i_in] >= ll_lon))!=inside_last) {
942  x_tmp[i_out] = ll_lon;
943  y_tmp[i_out++] = y_last + (ll_lon - x_last) * (lat_in[i_in] - y_last) / (lon_in[i_in] - x_last);
944  }
945 
946  /* if "to" point is right of LEFT boundary, output it */
947  if (inside) {
948  x_tmp[i_out] = lon_in[i_in];
949  y_tmp[i_out++] = lat_in[i_in];
950  }
951  x_last = lon_in[i_in];
952  y_last = lat_in[i_in];
953  inside_last = inside;
954  }
955  if (!(n_out=i_out)) return(0);
956 
957  /* clip polygon with RIGHT boundary - clip V_TMP to V_OUT */
958  x_last = x_tmp[n_out-1];
959  y_last = y_tmp[n_out-1];
960  inside_last = (x_last <= ur_lon);
961  for (i_in=0,i_out=0;i_in<n_out;i_in++) {
962 
963  /* if crossing RIGHT boundary - output intersection */
964  if ((inside=(x_tmp[i_in] <= ur_lon))!=inside_last) {
965  lon_out[i_out] = ur_lon;
966  lat_out[i_out++] = y_last + (ur_lon - x_last) * (y_tmp[i_in] - y_last)
967  / (x_tmp[i_in] - x_last);
968  }
969 
970  /* if "to" point is left of RIGHT boundary, output it */
971  if (inside) {
972  lon_out[i_out] = x_tmp[i_in];
973  lat_out[i_out++] = y_tmp[i_in];
974  }
975 
976  x_last = x_tmp[i_in];
977  y_last = y_tmp[i_in];
978  inside_last = inside;
979  }
980  if (!(n_out=i_out)) return(0);
981 
982  /* clip polygon with BOTTOM boundary - clip V_OUT to V_TMP */
983  x_last = lon_out[n_out-1];
984  y_last = lat_out[n_out-1];
985  inside_last = (y_last >= ll_lat);
986  for (i_in=0,i_out=0;i_in<n_out;i_in++) {
987 
988  /* if crossing BOTTOM boundary - output intersection */
989  if ((inside=(lat_out[i_in] >= ll_lat))!=inside_last) {
990  y_tmp[i_out] = ll_lat;
991  x_tmp[i_out++] = x_last + (ll_lat - y_last) * (lon_out[i_in] - x_last) / (lat_out[i_in] - y_last);
992  }
993 
994  /* if "to" point is above BOTTOM boundary, output it */
995  if (inside) {
996  x_tmp[i_out] = lon_out[i_in];
997  y_tmp[i_out++] = lat_out[i_in];
998  }
999  x_last = lon_out[i_in];
1000  y_last = lat_out[i_in];
1001  inside_last = inside;
1002  }
1003  if (!(n_out=i_out)) return(0);
1004 
1005  /* clip polygon with TOP boundary - clip V_TMP to V_OUT */
1006  x_last = x_tmp[n_out-1];
1007  y_last = y_tmp[n_out-1];
1008  inside_last = (y_last <= ur_lat);
1009  for (i_in=0,i_out=0;i_in<n_out;i_in++) {
1010 
1011  /* if crossing TOP boundary - output intersection */
1012  if ((inside=(y_tmp[i_in] <= ur_lat))!=inside_last) {
1013  lat_out[i_out] = ur_lat;
1014  lon_out[i_out++] = x_last + (ur_lat - y_last) * (x_tmp[i_in] - x_last) / (y_tmp[i_in] - y_last);
1015  }
1016 
1017  /* if "to" point is below TOP boundary, output it */
1018  if (inside) {
1019  lon_out[i_out] = x_tmp[i_in];
1020  lat_out[i_out++] = y_tmp[i_in];
1021  }
1022  x_last = x_tmp[i_in];
1023  y_last = y_tmp[i_in];
1024  inside_last = inside;
1025  }
1026  return(i_out);
1027 } /* clip */
1028 
1029 
1030 /*******************************************************************************
1031  Revise Sutherland-Hodgeman algorithm to find the vertices of the overlapping
1032  between any two grid boxes. It return the number of vertices for the exchange grid.
1033 *******************************************************************************/
1034 
1035 int clip_2dx2d(const double lon1_in[], const double lat1_in[], int n1_in,
1036  const double lon2_in[], const double lat2_in[], int n2_in,
1037  double lon_out[], double lat_out[])
1038 {
1039  double lon_tmp[MV], lat_tmp[MV];
1040  double x1_0, y1_0, x1_1, y1_1, x2_0, y2_0, x2_1, y2_1;
1041  double dx1, dy1, dx2, dy2, determ, ds1, ds2;
1042  int i_out, n_out, inside_last, inside, i1, i2;
1043 
1044  /* clip polygon with each boundary of the polygon */
1045  /* We treat lon1_in/lat1_in as clip polygon and lon2_in/lat2_in as subject polygon */
1046  n_out = n1_in;
1047  for(i1=0; i1<n1_in; i1++) {
1048  lon_tmp[i1] = lon1_in[i1];
1049  lat_tmp[i1] = lat1_in[i1];
1050  }
1051  x2_0 = lon2_in[n2_in-1];
1052  y2_0 = lat2_in[n2_in-1];
1053  for(i2=0; i2<n2_in; i2++) {
1054  x2_1 = lon2_in[i2];
1055  y2_1 = lat2_in[i2];
1056  x1_0 = lon_tmp[n_out-1];
1057  y1_0 = lat_tmp[n_out-1];
1058  inside_last = inside_edge( x2_0, y2_0, x2_1, y2_1, x1_0, y1_0);
1059  for(i1=0, i_out=0; i1<n_out; i1++) {
1060  x1_1 = lon_tmp[i1];
1061  y1_1 = lat_tmp[i1];
1062  if((inside = inside_edge(x2_0, y2_0, x2_1, y2_1, x1_1, y1_1)) != inside_last ) {
1063  /* there is intersection, the line between <x1_0,y1_0> and <x1_1,y1_1>
1064  should not parallel to the line between <x2_0,y2_0> and <x2_1,y2_1>
1065  may need to consider truncation error */
1066  dy1 = y1_1-y1_0;
1067  dy2 = y2_1-y2_0;
1068  dx1 = x1_1-x1_0;
1069  dx2 = x2_1-x2_0;
1070  ds1 = y1_0*x1_1 - y1_1*x1_0;
1071  ds2 = y2_0*x2_1 - y2_1*x2_0;
1072  determ = dy2*dx1 - dy1*dx2;
1073  if(fabs(determ) < EPSLN30) {
1074  error_handler("the line between <x1_0,y1_0> and <x1_1,y1_1> should not parallel to "
1075  "the line between <x2_0,y2_0> and <x2_1,y2_1>");
1076  }
1077  lon_out[i_out] = (dx2*ds1 - dx1*ds2)/determ;
1078  lat_out[i_out++] = (dy2*ds1 - dy1*ds2)/determ;
1079 
1080 
1081  }
1082  if(inside) {
1083  lon_out[i_out] = x1_1;
1084  lat_out[i_out++] = y1_1;
1085  }
1086  x1_0 = x1_1;
1087  y1_0 = y1_1;
1088  inside_last = inside;
1089  }
1090  if(!(n_out=i_out)) return 0;
1091  for(i1=0; i1<n_out; i1++) {
1092  lon_tmp[i1] = lon_out[i1];
1093  lat_tmp[i1] = lat_out[i1];
1094  }
1095  /* shift the starting point */
1096  x2_0 = x2_1;
1097  y2_0 = y2_1;
1098  }
1099  return(n_out);
1100 } /* clip */
1101 
1102 
1103 /*******************************************************************************
1104  Revise Sutherland-Hodgeman algorithm to find the vertices of the overlapping
1105  between any two grid boxes. It return the number of vertices for the exchange grid.
1106  Each edge of grid box is a part of great circle. All the points are cartesian
1107  coordinates. Here we are assuming each polygon is convex.
1108  RANGE_CHECK_CRITERIA is used to determine if the two grid boxes are possible to be
1109  overlap. The size should be between 0 and 0.5. The larger the range_check_criteria,
1110  the more expensive of the computatioin. When the value is close to 0,
1111  some small exchange grid might be lost. Suggest to use value 0.05 for C48.
1112 *******************************************************************************/
1113 
1114 int clip_2dx2d_great_circle(const double x1_in[], const double y1_in[], const double z1_in[], int n1_in,
1115  const double x2_in[], const double y2_in[], const double z2_in [], int n2_in,
1116  double x_out[], double y_out[], double z_out[])
1117 {
1118  struct Node *grid1List=NULL;
1119  struct Node *grid2List=NULL;
1120  struct Node *intersectList=NULL;
1121  struct Node *polyList=NULL;
1122  struct Node *curList=NULL;
1123  struct Node *firstIntersect=NULL, *curIntersect=NULL;
1124  struct Node *temp1=NULL, *temp2=NULL, *temp=NULL;
1125 
1126  int i1, i2, i1p, i2p, i2p2, npts1, npts2;
1127  int nintersect, n_out;
1128  int maxiter1, maxiter2, iter1, iter2;
1129  int found1, found2, curListNum;
1130  int has_inbound, inbound;
1131  double pt1[MV][3], pt2[MV][3];
1132  double *p1_0=NULL, *p1_1=NULL;
1133  double *p2_0=NULL, *p2_1=NULL, *p2_2=NULL;
1134  double intersect[3];
1135  double u1, u2;
1136  double min_x1, max_x1, min_y1, max_y1, min_z1, max_z1;
1137  double min_x2, max_x2, min_y2, max_y2, min_z2, max_z2;
1138 
1139 
1140  /* first check the min and max of (x1_in, y1_in, z1_in) with (x2_in, y2_in, z2_in) */
1141  min_x1 = minval_double(n1_in, x1_in);
1142  max_x2 = maxval_double(n2_in, x2_in);
1143  if(min_x1 >= max_x2+RANGE_CHECK_CRITERIA) return 0;
1144  max_x1 = maxval_double(n1_in, x1_in);
1145  min_x2 = minval_double(n2_in, x2_in);
1146  if(min_x2 >= max_x1+RANGE_CHECK_CRITERIA) return 0;
1147 
1148  min_y1 = minval_double(n1_in, y1_in);
1149  max_y2 = maxval_double(n2_in, y2_in);
1150  if(min_y1 >= max_y2+RANGE_CHECK_CRITERIA) return 0;
1151  max_y1 = maxval_double(n1_in, y1_in);
1152  min_y2 = minval_double(n2_in, y2_in);
1153  if(min_y2 >= max_y1+RANGE_CHECK_CRITERIA) return 0;
1154 
1155  min_z1 = minval_double(n1_in, z1_in);
1156  max_z2 = maxval_double(n2_in, z2_in);
1157  if(min_z1 >= max_z2+RANGE_CHECK_CRITERIA) return 0;
1158  max_z1 = maxval_double(n1_in, z1_in);
1159  min_z2 = minval_double(n2_in, z2_in);
1160  if(min_z2 >= max_z1+RANGE_CHECK_CRITERIA) return 0;
1161 
1162  rewindList();
1163 
1164  grid1List = getNext();
1165  grid2List = getNext();
1166  intersectList = getNext();
1167  polyList = getNext();
1168 
1169  /* insert points into SubjList and ClipList */
1170  for(i1=0; i1<n1_in; i1++) addEnd(grid1List, x1_in[i1], y1_in[i1], z1_in[i1], 0, 0, 0, -1);
1171  for(i2=0; i2<n2_in; i2++) addEnd(grid2List, x2_in[i2], y2_in[i2], z2_in[i2], 0, 0, 0, -1);
1172  npts1 = length(grid1List);
1173  npts2 = length(grid2List);
1174 
1175  n_out = 0;
1176  /* set the inside value */
1177  /* first check number of points in grid1 is inside grid2 */
1178 
1179  temp = grid1List;
1180  while(temp) {
1181  if(insidePolygon(temp, grid2List))
1182  temp->isInside = 1;
1183  else
1184  temp->isInside = 0;
1185  temp = getNextNode(temp);
1186  }
1187 
1188  /* check if grid2List is inside grid1List */
1189  temp = grid2List;
1190 
1191  while(temp) {
1192  if(insidePolygon(temp, grid1List))
1193  temp->isInside = 1;
1194  else
1195  temp->isInside = 0;
1196  temp = getNextNode(temp);
1197  }
1198 
1199  /* make sure the grid box is clockwise */
1200 
1201  /*make sure each polygon is convex, which is equivalent that the great_circle_area is positive */
1202  if( gridArea(grid1List) <= 0 )
1203  error_handler("create_xgrid.c(clip_2dx2d_great_circle): grid box 1 is not convex");
1204  if( gridArea(grid2List) <= 0 )
1205  error_handler("create_xgrid.c(clip_2dx2d_great_circle): grid box 2 is not convex");
1206 
1207  /* get the coordinates from grid1List and grid2List.
1208  Please not npts1 might not equal n1_in, npts2 might not equal n2_in because of pole
1209  */
1210 
1211  temp = grid1List;
1212  for(i1=0; i1<npts1; i1++) {
1213  getCoordinates(temp, pt1[i1]);
1214  temp = temp->Next;
1215  }
1216  temp = grid2List;
1217  for(i2=0; i2<npts2; i2++) {
1218  getCoordinates(temp, pt2[i2]);
1219  temp = temp->Next;
1220  }
1221 
1222  firstIntersect=getNext();
1223  curIntersect = getNext();
1224 
1225  /* first find all the intersection points */
1226  nintersect = 0;
1227  for(i1=0; i1<npts1; i1++) {
1228  i1p = (i1+1)%npts1;
1229  p1_0 = pt1[i1];
1230  p1_1 = pt1[i1p];
1231  for(i2=0; i2<npts2; i2++) {
1232  i2p = (i2+1)%npts2;
1233  i2p2 = (i2+2)%npts2;
1234  p2_0 = pt2[i2];
1235  p2_1 = pt2[i2p];
1236  p2_2 = pt2[i2p2];
1237  if( line_intersect_2D_3D(p1_0, p1_1, p2_0, p2_1, p2_2, intersect, &u1, &u2, &inbound) ) {
1238  /* from the value of u1, u2 and inbound, we can partially decide if a point is inside or outside of polygon */
1239 
1240  /* add the intersection into intersetList, The intersection might already be in
1241  intersectList and will be taken care addIntersect
1242  */
1243  if(addIntersect(intersectList, intersect[0], intersect[1], intersect[2], 1, u1, u2, inbound, i1, i1p, i2, i2p)) {
1244  /* add the intersection into the grid1List */
1245 
1246  if(u1 == 1) {
1247  insertIntersect(grid1List, intersect[0], intersect[1], intersect[2], 0.0, u2, inbound, p1_1[0], p1_1[1], p1_1[2]);
1248  }
1249  else
1250  insertIntersect(grid1List, intersect[0], intersect[1], intersect[2], u1, u2, inbound, p1_0[0], p1_0[1], p1_0[2]);
1251  /* when u1 == 0 or 1, need to adjust the vertice to intersect value for roundoff error */
1252  if(u1==1) {
1253  p1_1[0] = intersect[0];
1254  p1_1[1] = intersect[1];
1255  p1_1[2] = intersect[2];
1256  }
1257  else if(u1 == 0) {
1258  p1_0[0] = intersect[0];
1259  p1_0[1] = intersect[1];
1260  p1_0[2] = intersect[2];
1261  }
1262  /* add the intersection into the grid2List */
1263  if(u2==1)
1264  insertIntersect(grid2List, intersect[0], intersect[1], intersect[2], 0.0, u1, 0, p2_1[0], p2_1[1], p2_1[2]);
1265  else
1266  insertIntersect(grid2List, intersect[0], intersect[1], intersect[2], u2, u1, 0, p2_0[0], p2_0[1], p2_0[2]);
1267  /* when u2 == 0 or 1, need to adjust the vertice to intersect value for roundoff error */
1268  if(u2==1) {
1269  p2_1[0] = intersect[0];
1270  p2_1[1] = intersect[1];
1271  p2_1[2] = intersect[2];
1272  }
1273  else if(u2 == 0) {
1274  p2_0[0] = intersect[0];
1275  p2_0[1] = intersect[1];
1276  p2_0[2] = intersect[2];
1277  }
1278  }
1279  }
1280  }
1281  }
1282 
1283  /* set inbound value for the points in intersectList that has inbound == 0,
1284  this will also set some inbound value of the points in grid1List
1285  */
1286 
1287  /* get the first point in intersectList has inbound = 2, if not, set inbound value */
1288  has_inbound = 0;
1289  /* loop through intersectList to see if there is any has inbound=1 or 2 */
1290  temp = intersectList;
1291  nintersect = length(intersectList);
1292  if(nintersect > 1) {
1293  getFirstInbound(intersectList, firstIntersect);
1294  if(firstIntersect->initialized) {
1295  has_inbound = 1;
1296  }
1297  }
1298 
1299  /* when has_inbound == 0, get the grid1List and grid2List */
1300  if( !has_inbound && nintersect > 1) {
1301  setInbound(intersectList, grid1List);
1302  getFirstInbound(intersectList, firstIntersect);
1303  if(firstIntersect->initialized) has_inbound = 1;
1304  }
1305 
1306  /* if has_inbound = 1, find the overlapping */
1307  n_out = 0;
1308 
1309  if(has_inbound) {
1310  maxiter1 = nintersect;
1311  temp1 = getNode(grid1List, *firstIntersect);
1312  if( temp1 == NULL) {
1313  double lon[10], lat[10];
1314  int i;
1315  xyz2latlon(n1_in, x1_in, y1_in, z1_in, lon, lat);
1316  for(i=0; i< n1_in; i++) printf("lon1 = %g, lat1 = %g\n", lon[i]*R2D, lat[i]*R2D);
1317  printf("\n");
1318  xyz2latlon(n2_in, x2_in, y2_in, z2_in, lon, lat);
1319  for(i=0; i< n2_in; i++) printf("lon2 = %g, lat2 = %g\n", lon[i]*R2D, lat[i]*R2D);
1320  printf("\n");
1321 
1322  error_handler("firstIntersect is not in the grid1List");
1323  }
1324  addNode(polyList, *firstIntersect);
1325  nintersect--;
1326 
1327  /* Loop over the grid1List and grid2List to find again the firstIntersect */
1328  curList = grid1List;
1329  curListNum = 0;
1330 
1331  /* Loop through curList to find the next intersection, the loop will end
1332  when come back to firstIntersect
1333  */
1334  copyNode(curIntersect, *firstIntersect);
1335  iter1 = 0;
1336  found1 = 0;
1337 
1338  while( iter1 < maxiter1 ) {
1339  /* find the curIntersect in curList and get the next intersection points */
1340  temp1 = getNode(curList, *curIntersect);
1341  temp2 = temp1->Next;
1342  if( temp2 == NULL ) temp2 = curList;
1343 
1344  maxiter2 = length(curList);
1345  found2 = 0;
1346  iter2 = 0;
1347  /* Loop until find the next intersection */
1348  while( iter2 < maxiter2 ) {
1349  int temp2IsIntersect;
1350 
1351  temp2IsIntersect = 0;
1352  if( isIntersect( *temp2 ) ) { /* copy the point and switch to the grid2List */
1353  struct Node *temp3;
1354 
1355  /* first check if temp2 is the firstIntersect */
1356  if( sameNode( *temp2, *firstIntersect) ) {
1357  found1 = 1;
1358  break;
1359  }
1360 
1361  temp3 = temp2->Next;
1362  if( temp3 == NULL) temp3 = curList;
1363  if( temp3 == NULL) error_handler("creat_xgrid.c: temp3 can not be NULL");
1364  found2 = 1;
1365  /* if next node is inside or an intersection,
1366  need to keep on curList
1367  */
1368  temp2IsIntersect = 1;
1369  if( isIntersect(*temp3) || (temp3->isInside == 1) ) found2 = 0;
1370  }
1371  if(found2) {
1372  copyNode(curIntersect, *temp2);
1373  break;
1374  }
1375  else {
1376  addNode(polyList, *temp2);
1377  if(temp2IsIntersect) {
1378  nintersect--;
1379  }
1380  }
1381  temp2 = temp2->Next;
1382  if( temp2 == NULL ) temp2 = curList;
1383  iter2 ++;
1384  }
1385  if(found1) break;
1386 
1387  if( !found2 ) error_handler(" not found the next intersection ");
1388 
1389  /* if find the first intersection, the poly found */
1390  if( sameNode( *curIntersect, *firstIntersect) ) {
1391  found1 = 1;
1392  break;
1393  }
1394 
1395  /* add curIntersect to polyList and remove it from intersectList and curList */
1396  addNode(polyList, *curIntersect);
1397  nintersect--;
1398 
1399 
1400  /* switch curList */
1401  if( curListNum == 0) {
1402  curList = grid2List;
1403  curListNum = 1;
1404  }
1405  else {
1406  curList = grid1List;
1407  curListNum = 0;
1408  }
1409  iter1++;
1410  }
1411  if(!found1) error_handler("not return back to the first intersection");
1412 
1413  /* currently we are only clipping convex polygon to convex polygon */
1414  if( nintersect > 0) error_handler("After clipping, nintersect should be 0");
1415 
1416  /* copy the polygon to x_out, y_out, z_out */
1417  temp1 = polyList;
1418  while (temp1 != NULL) {
1419  getCoordinate(*temp1, x_out+n_out, y_out+n_out, z_out+n_out);
1420  temp1 = temp1->Next;
1421  n_out++;
1422  }
1423 
1424  /* if(n_out < 3) error_handler(" The clipped region has < 3 vertices"); */
1425  if( n_out < 3) n_out = 0;
1426  }
1427 
1428  /* check if grid1 is inside grid2 */
1429  if(n_out==0){
1430  /* first check number of points in grid1 is inside grid2 */
1431  int n, n1in2;
1432  /* One possible is that grid1List is inside grid2List */
1433  n1in2 = 0;
1434  temp = grid1List;
1435  while(temp) {
1436  if(temp->intersect != 1) {
1437  if( temp->isInside == 1) n1in2++;
1438  }
1439  temp = getNextNode(temp);
1440  }
1441  if(npts1==n1in2) { /* grid1 is inside grid2 */
1442  n_out = npts1;
1443  n = 0;
1444  temp = grid1List;
1445  while( temp ) {
1446  getCoordinate(*temp, &x_out[n], &y_out[n], &z_out[n]);
1447  n++;
1448  temp = getNextNode(temp);
1449  }
1450  }
1451  if(n_out>0) return n_out;
1452  }
1453 
1454  /* check if grid2List is inside grid1List */
1455  if(n_out ==0){
1456  int n, n2in1;
1457 
1458  temp = grid2List;
1459  n2in1 = 0;
1460  while(temp) {
1461  if(temp->intersect != 1) {
1462  if( temp->isInside == 1) n2in1++;
1463  }
1464  temp = getNextNode(temp);
1465  }
1466 
1467  if(npts2==n2in1) { /* grid2 is inside grid1 */
1468  n_out = npts2;
1469  n = 0;
1470  temp = grid2List;
1471  while( temp ) {
1472  getCoordinate(*temp, &x_out[n], &y_out[n], &z_out[n]);
1473  n++;
1474  temp = getNextNode(temp);
1475  }
1476 
1477  }
1478  }
1479 
1480 
1481  return n_out;
1482 }
1483 
1484 
1485 /* Intersects between the line a and the seqment s
1486  where both line and segment are great circle lines on the sphere represented by
1487  3D cartesian points.
1488  [sin sout] are the ends of a line segment
1489  returns true if the lines could be intersected, false otherwise.
1490  inbound means the direction of (a1,a2) go inside or outside of (q1,q2,q3)
1491 */
1492 
1493 int line_intersect_2D_3D(double *a1, double *a2, double *q1, double *q2, double *q3,
1494  double *intersect, double *u_a, double *u_q, int *inbound){
1495 
1496  /* Do this intersection by reprsenting the line a1 to a2 as a plane through the
1497  two line points and the origin of the sphere (0,0,0). This is the
1498  definition of a great circle arc.
1499  */
1500  double plane[9];
1501  double plane_p[2];
1502  double u;
1503  double p1[3], v1[3], v2[3];
1504  double c1[3], c2[3], c3[3];
1505  double coincident, sense, norm;
1506  int i;
1507  int is_inter1, is_inter2;
1508 
1509  *inbound = 0;
1510 
1511  /* first check if any vertices are the same */
1512  if(samePoint(a1[0], a1[1], a1[2], q1[0], q1[1], q1[2])) {
1513  *u_a = 0;
1514  *u_q = 0;
1515  intersect[0] = a1[0];
1516  intersect[1] = a1[1];
1517  intersect[2] = a1[2];
1518  return 1;
1519  }
1520  else if (samePoint(a1[0], a1[1], a1[2], q2[0], q2[1], q2[2])) {
1521  *u_a = 0;
1522  *u_q = 1;
1523  intersect[0] = a1[0];
1524  intersect[1] = a1[1];
1525  intersect[2] = a1[2];
1526  return 1;
1527  }
1528  else if(samePoint(a2[0], a2[1], a2[2], q1[0], q1[1], q1[2])) {
1529  *u_a = 1;
1530  *u_q = 0;
1531  intersect[0] = a2[0];
1532  intersect[1] = a2[1];
1533  intersect[2] = a2[2];
1534  return 1;
1535  }
1536  else if (samePoint(a2[0], a2[1], a2[2], q2[0], q2[1], q2[2])) {
1537  *u_a = 1;
1538  *u_q = 1;
1539  intersect[0] = a2[0];
1540  intersect[1] = a2[1];
1541  intersect[2] = a2[2];
1542  return 1;
1543  }
1544 
1545 
1546  /* Load points defining plane into variable (these are supposed to be in counterclockwise order) */
1547  plane[0]=q1[0];
1548  plane[1]=q1[1];
1549  plane[2]=q1[2];
1550  plane[3]=q2[0];
1551  plane[4]=q2[1];
1552  plane[5]=q2[2];
1553  plane[6]=0.0;
1554  plane[7]=0.0;
1555  plane[8]=0.0;
1556 
1557  /* Intersect the segment with the plane */
1558  is_inter1 = intersect_tri_with_line(plane, a1, a2, plane_p, u_a);
1559 
1560  if(!is_inter1)
1561  return 0;
1562 
1563  if(fabs(*u_a) < EPSLN8) *u_a = 0;
1564  if(fabs(*u_a-1) < EPSLN8) *u_a = 1;
1565 
1566 
1567  if( (*u_a < 0) || (*u_a > 1) ) return 0;
1568 
1569  /* Load points defining plane into variable (these are supposed to be in counterclockwise order) */
1570  plane[0]=a1[0];
1571  plane[1]=a1[1];
1572  plane[2]=a1[2];
1573  plane[3]=a2[0];
1574  plane[4]=a2[1];
1575  plane[5]=a2[2];
1576  plane[6]=0.0;
1577  plane[7]=0.0;
1578  plane[8]=0.0;
1579 
1580  /* Intersect the segment with the plane */
1581  is_inter2 = intersect_tri_with_line(plane, q1, q2, plane_p, u_q);
1582 
1583  if(!is_inter2)
1584  return 0;
1585 
1586  if(fabs(*u_q) < EPSLN8) *u_q = 0;
1587  if(fabs(*u_q-1) < EPSLN8) *u_q = 1;
1588 
1589 
1590  if( (*u_q < 0) || (*u_q > 1) ) return 0;
1591 
1592  u =*u_a;
1593 
1594  /* The two planes are coincidental */
1595  vect_cross(a1, a2, c1);
1596  vect_cross(q1, q2, c2);
1597  vect_cross(c1, c2, c3);
1598  coincident = metric(c3);
1599 
1600  if(fabs(coincident) < EPSLN30) return 0;
1601 
1602  /* Calculate point of intersection */
1603  intersect[0]=a1[0] + u*(a2[0]-a1[0]);
1604  intersect[1]=a1[1] + u*(a2[1]-a1[1]);
1605  intersect[2]=a1[2] + u*(a2[2]-a1[2]);
1606 
1607  norm = metric( intersect );
1608  for(i = 0; i < 3; i ++) intersect[i] /= norm;
1609 
1610  /* when u_q =0 or u_q =1, the following could not decide the inbound value */
1611  if(*u_q != 0 && *u_q != 1){
1612 
1613  p1[0] = a2[0]-a1[0];
1614  p1[1] = a2[1]-a1[1];
1615  p1[2] = a2[2]-a1[2];
1616  v1[0] = q2[0]-q1[0];
1617  v1[1] = q2[1]-q1[1];
1618  v1[2] = q2[2]-q1[2];
1619  v2[0] = q3[0]-q2[0];
1620  v2[1] = q3[1]-q2[1];
1621  v2[2] = q3[2]-q2[2];
1622 
1623  vect_cross(v1, v2, c1);
1624  vect_cross(v1, p1, c2);
1625 
1626  sense = dot(c1, c2);
1627  *inbound = 1;
1628  if(sense > 0) *inbound = 2; /* v1 going into v2 in CCW sense */
1629  }
1630 
1631  return 1;
1632 }
1633 
1634 
1635 /*------------------------------------------------------------------------------
1636  double poly_ctrlat(const double x[], const double y[], int n)
1637  This routine is used to calculate the latitude of the centroid
1638  ---------------------------------------------------------------------------*/
1639 
1640 double poly_ctrlat(const double x[], const double y[], int n)
1641 {
1642  double ctrlat = 0.0;
1643  int i;
1644 
1645  for (i=0;i<n;i++) {
1646  int ip = (i+1) % n;
1647  double dx = (x[ip]-x[i]);
1648  double dy, avg_y, hdy;
1649  double lat1, lat2;
1650  lat1 = y[ip];
1651  lat2 = y[i];
1652  dy = lat2 - lat1;
1653  hdy = dy*0.5;
1654  avg_y = (lat1+lat2)*0.5;
1655  if (dx==0.0) continue;
1656  if(dx > M_PI) dx = dx - 2.0*M_PI;
1657  if(dx < -M_PI) dx = dx + 2.0*M_PI;
1658 
1659  if ( fabs(hdy)< SMALL_VALUE ) /* cheap area calculation along latitude */
1660  ctrlat -= dx*(2*cos(avg_y) + lat2*sin(avg_y) - cos(lat1) );
1661  else
1662  ctrlat -= dx*( (sin(hdy)/hdy)*(2*cos(avg_y) + lat2*sin(avg_y)) - cos(lat1) );
1663  }
1664  return (ctrlat*RADIUS*RADIUS);
1665 } /* poly_ctrlat */
1666 
1667 /*------------------------------------------------------------------------------
1668  double poly_ctrlon(const double x[], const double y[], int n, double clon)
1669  This routine is used to calculate the lontitude of the centroid.
1670  ---------------------------------------------------------------------------*/
1671 double poly_ctrlon(const double x[], const double y[], int n, double clon)
1672 {
1673  double ctrlon = 0.0;
1674  int i;
1675 
1676  for (i=0;i<n;i++) {
1677  int ip = (i+1) % n;
1678  double phi1, phi2, dphi, lat1, lat2, dphi1, dphi2;
1679  double f1, f2, fac, fint;
1680  phi1 = x[ip];
1681  phi2 = x[i];
1682  lat1 = y[ip];
1683  lat2 = y[i];
1684  dphi = phi1 - phi2;
1685 
1686  if (dphi==0.0) continue;
1687 
1688  f1 = 0.5*(cos(lat1)*sin(lat1)+lat1);
1689  f2 = 0.5*(cos(lat2)*sin(lat2)+lat2);
1690 
1691  /* this will make sure longitude of centroid is at
1692  the same interval as the center of any grid */
1693  if(dphi > M_PI) dphi = dphi - 2.0*M_PI;
1694  if(dphi < -M_PI) dphi = dphi + 2.0*M_PI;
1695  dphi1 = phi1 - clon;
1696  if( dphi1 > M_PI) dphi1 -= 2.0*M_PI;
1697  if( dphi1 <-M_PI) dphi1 += 2.0*M_PI;
1698  dphi2 = phi2 -clon;
1699  if( dphi2 > M_PI) dphi2 -= 2.0*M_PI;
1700  if( dphi2 <-M_PI) dphi2 += 2.0*M_PI;
1701 
1702  if(fabs(dphi2 -dphi1) < M_PI) {
1703  ctrlon -= dphi * (dphi1*f1+dphi2*f2)/2.0;
1704  }
1705  else {
1706  if(dphi1 > 0.0)
1707  fac = M_PI;
1708  else
1709  fac = -M_PI;
1710  fint = f1 + (f2-f1)*(fac-dphi1)/fabs(dphi);
1711  ctrlon -= 0.5*dphi1*(dphi1-fac)*f1 - 0.5*dphi2*(dphi2+fac)*f2
1712  + 0.5*fac*(dphi1+dphi2)*fint;
1713  }
1714 
1715  }
1716  return (ctrlon*RADIUS*RADIUS);
1717 } /* poly_ctrlon */
1718 
1719 /*******************************************************************************
1720  int inside_edge(double x0, double y0, double x1, double y1, double x, double y)
1721  determine a point(x,y) is inside or outside a given edge with vertex,
1722  (x0,y0) and (x1,y1). return 1 if inside and 0 if outside. <y1-y0, -(x1-x0)> is
1723  the outward edge normal from vertex <x0,y0> to <x1,y1>. <x-x0,y-y0> is the vector
1724  from <x0,y0> to <x,y>.
1725  if Inner produce <x-x0,y-y0>*<y1-y0, -(x1-x0)> > 0, outside, otherwise inside.
1726  inner product value = 0 also treate as inside.
1727 *******************************************************************************/
1728 int inside_edge(double x0, double y0, double x1, double y1, double x, double y)
1729 {
1730  const double SMALL = 1.e-12;
1731  double product;
1732 
1733  product = ( x-x0 )*(y1-y0) + (x0-x1)*(y-y0);
1734  return (product<=SMALL) ? 1:0;
1735 
1736 } /* inside_edge */
pure elemental type(point) function latlon2xyz(lat, lon)
Return the (x,y,z) position of a given (lat,lon) point.
Definition: diag_grid.F90:1018
real(r8_kind), dimension(:,:), allocatable area
area of each grid box
integer nlat
No description.
integer nlon
No description.
integer sense
No description.
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.
Definition: mpp_util.inc:50