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