FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
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
41void 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*******************************************************************************/
56double 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*******************************************************************************/
75double 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*******************************************************************************/
93double 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******************************************************************************/
111void 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 ----------------------------------------------------------*/
127void 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
154int 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
164int 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
178void 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
187int 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 ----------------------------------------------------------------------------*/
266double 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 -----------------------------------------------------------------------------*/
290double 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
331void 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
346double 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
354double metric(const double *p) {
355 return (sqrt(p[0]*p[0] + p[1]*p[1]+p[2]*p[2]) );
356}
357
358void 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 ---------------------------------------------------------------------*/
374void 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*/
404int 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
445void 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 */
455int 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
481int 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
525int 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
536double get_global_area(void)
537{
538 double garea;
539 garea = 4*M_PI*RADIUS*RADIUS;
540
541 return garea;
542}
543
544double get_global_area_(void)
545{
546 double garea;
547 garea = 4*M_PI*RADIUS*RADIUS;
548
549 return garea;
550}
551
552double 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
584double 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 ----------------------------------------------------------------------------*/
616double 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 */
649double 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 ----------------------------------------------------------------------------*/
682double 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/*******************************************************************************
719void get_grid_area(const int *nlon, const int *nlat, const double *lon, const double *lat, const double *area)
720 return the grid area.
721*******************************************************************************/
722void 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
727void 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/*******************************************************************************
753void get_grid_area_ug(const int *npts, const double *lon, const double *lat, const double *area)
754 return the grid area.
755*******************************************************************************/
756void 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
761void 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
785void 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
791void 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
831void 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
837void 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
874void 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
900void 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
929int 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
1036int 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
1115int 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
1494int 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
1641double 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 ---------------------------------------------------------------------------*/
1672double 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*******************************************************************************/
1729int 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.
real(r8_kind), dimension(:,:), allocatable area
area of each grid box
integer nlat
No description.
integer nlon
No description.
integer sense
No description.