FMS  2025.01.02-dev
Flexible Modeling System
tree_utils.c
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 /** \file
28  * \ingroup tree_utils
29  * \brief utilities for create_xgrid_great_circle
30  */
31 
32 struct Node *nodeList=NULL;
33 int curListPos=0;
34 
35 void rewindList(void)
36 {
37  int n;
38 
39  curListPos = 0;
40  if(!nodeList) nodeList = (struct Node *)malloc(MAXNODELIST*sizeof(struct Node));
41  for(n=0; n<MAXNODELIST; n++) initNode(nodeList+n);
42 
43 }
44 
45 struct Node *getNext()
46 {
47  struct Node *temp=NULL;
48  int n;
49 
50  if(!nodeList) {
51  nodeList = (struct Node *)malloc(MAXNODELIST*sizeof(struct Node));
52  for(n=0; n<MAXNODELIST; n++) initNode(nodeList+n);
53  }
54 
55  temp = nodeList+curListPos;
56  curListPos++;
57  if(curListPos > MAXNODELIST) error_handler("getNext: curListPos >= MAXNODELIST");
58 
59  return (temp);
60 }
61 
62 
63 void initNode(struct Node *node)
64 {
65  node->x = 0;
66  node->y = 0;
67  node->z = 0;
68  node->u = 0;
69  node->intersect = 0;
70  node->inbound = 0;
71  node->isInside = 0;
72  node->Next = NULL;
73  node->initialized=0;
74 
75 }
76 
77 void addEnd(struct Node *list, double x, double y, double z, int intersect, double u, int inbound, int inside)
78 {
79 
80  struct Node *temp=NULL;
81 
82  if(list == NULL) error_handler("addEnd: list is NULL");
83 
84  if(list->initialized) {
85 
86  /* (x,y,z) might already in the list when intersect is true and u=0 or 1 */
87  temp = list;
88  while (temp) {
89  if(samePoint(temp->x, temp->y, temp->z, x, y, z)) return;
90  temp=temp->Next;
91  }
92  temp = list;
93  while(temp->Next)
94  temp=temp->Next;
95 
96  /* Append at the end of the list. */
97  temp->Next = getNext();
98  temp = temp->Next;
99  }
100  else {
101  temp = list;
102  }
103 
104  temp->x = x;
105  temp->y = y;
106  temp->z = z;
107  temp->u = u;
108  temp->intersect = intersect;
109  temp->inbound = inbound;
110  temp->initialized=1;
111  temp->isInside = inside;
112 }
113 
114 /* return 1 if the point (x,y,z) is added in the list, return 0 if it is already in the list */
115 
116 int addIntersect(struct Node *list, double x, double y, double z, int intersect, double u1, double u2, int inbound,
117  int is1, int ie1, int is2, int ie2)
118 {
119 
120  double u1_cur, u2_cur;
121  int i1_cur, i2_cur;
122  struct Node *temp=NULL;
123 
124  if(list == NULL) error_handler("addEnd: list is NULL");
125 
126  /* first check to make sure this point is not in the list */
127  u1_cur = u1;
128  i1_cur = is1;
129  u2_cur = u2;
130  i2_cur = is2;
131  if(u1_cur == 1) {
132  u1_cur = 0;
133  i1_cur = ie1;
134  }
135  if(u2_cur == 1) {
136  u2_cur = 0;
137  i2_cur = ie2;
138  }
139 
140  if(list->initialized) {
141  temp = list;
142  while(temp) {
143  if( temp->u == u1_cur && temp->subj_index == i1_cur) return 0;
144  if( temp->u_clip == u2_cur && temp->clip_index == i2_cur) return 0;
145  if( !temp->Next ) break;
146  temp=temp->Next;
147  }
148 
149  /* Append at the end of the list. */
150  temp->Next = getNext();
151  temp = temp->Next;
152  }
153  else {
154  temp = list;
155  }
156 
157  temp->x = x;
158  temp->y = y;
159  temp->z = z;
160  temp->intersect = intersect;
161  temp->inbound = inbound;
162  temp->initialized=1;
163  temp->isInside = 0;
164  temp->u = u1_cur;
165  temp->subj_index = i1_cur;
166  temp->u_clip = u2_cur;
167  temp->clip_index = i2_cur;
168 
169  return 1;
170 }
171 
172 
173 int length(struct Node *list)
174 {
175  struct Node *cur_ptr=NULL;
176  int count=0;
177 
178  cur_ptr=list;
179 
180  while(cur_ptr)
181  {
182  if(cur_ptr->initialized ==0) break;
183  cur_ptr=cur_ptr->Next;
184  count++;
185  }
186  return(count);
187 }
188 
189 /* two points are the same if there are close enough */
190 int samePoint(double x1, double y1, double z1, double x2, double y2, double z2)
191 {
192  if( fabs(x1-x2) > EPSLN10 || fabs(y1-y2) > EPSLN10 || fabs(z1-z2) > EPSLN10 )
193  return 0;
194  else
195  return 1;
196 }
197 
198 
199 int sameNode(struct Node node1, struct Node node2)
200 {
201  if( node1.x == node2.x && node1.y == node2.y && node1.z==node2.z )
202  return 1;
203  else
204  return 0;
205 }
206 
207 
208 void addNode(struct Node *list, struct Node inNode)
209 {
210 
211  addEnd(list, inNode.x, inNode.y, inNode.z, inNode.intersect, inNode.u, inNode.inbound, inNode.isInside);
212 
213 }
214 
215 struct Node *getNode(struct Node *list, struct Node inNode)
216 {
217  struct Node *thisNode=NULL;
218  struct Node *temp=NULL;
219 
220  temp = list;
221  while( temp ) {
222  if( sameNode( *temp, inNode ) ) {
223  thisNode = temp;
224  temp = NULL;
225  break;
226  }
227  temp = temp->Next;
228  }
229 
230  return thisNode;
231 }
232 
233 struct Node *getNextNode(struct Node *list)
234 {
235  return list->Next;
236 }
237 
238 void copyNode(struct Node *node_out, struct Node node_in)
239 {
240 
241  node_out->x = node_in.x;
242  node_out->y = node_in.y;
243  node_out->z = node_in.z;
244  node_out->u = node_in.u;
245  node_out->intersect = node_in.intersect;
246  node_out->inbound = node_in.inbound;
247  node_out->Next = NULL;
248  node_out->initialized = node_in.initialized;
249  node_out->isInside = node_in.isInside;
250 }
251 
252 void printNode(struct Node *list, char *str)
253 {
254  struct Node *temp;
255 
256  if(list == NULL) error_handler("printNode: list is NULL");
257  if(str) printf(" %s \n", str);
258  temp = list;
259  while(temp) {
260  if(temp->initialized ==0) break;
261  printf(" (x, y, z, interset, inbound, isInside) = (%19.15f,%19.15f,%19.15f,%d,%d,%d)\n",
262  temp->x, temp->y, temp->z, temp->intersect, temp->inbound, temp->isInside);
263  temp = temp->Next;
264  }
265  printf("\n");
266 }
267 
268 int intersectInList(struct Node *list, double x, double y, double z)
269 {
270  struct Node *temp;
271  int found=0;
272 
273  temp = list;
274  found = 0;
275  while ( temp ) {
276  if( temp->x == x && temp->y == y && temp->z == z ) {
277  found = 1;
278  break;
279  }
280  temp=temp->Next;
281  }
282  if (!found) error_handler("intersectInList: point (x,y,z) is not found in the list");
283  if( temp->intersect == 2 )
284  return 1;
285  else
286  return 0;
287 
288 }
289 
290 
291 /* The following insert a intersection after non-intersect point (x2,y2,z2), if the point
292  after (x2,y2,z2) is an intersection, if u is greater than the u value of the intersection,
293  insert after, otherwise insert before
294 */
295 void insertIntersect(struct Node *list, double x, double y, double z, double u1, double u2, int inbound,
296  double x2, double y2, double z2)
297 {
298  struct Node *temp1=NULL, *temp2=NULL;
299  struct Node *temp;
300  double u_cur;
301  int found=0;
302 
303  temp1 = list;
304  found = 0;
305  while ( temp1 ) {
306  if( temp1->x == x2 && temp1->y == y2 && temp1->z == z2 ) {
307  found = 1;
308  break;
309  }
310  temp1=temp1->Next;
311  }
312  if (!found) error_handler("inserAfter: point (x,y,z) is not found in the list");
313 
314  /* when u = 0 or u = 1, set the grid point to be the intersection point to solve truncation error isuse */
315  u_cur = u1;
316  if(u1 == 1) {
317  u_cur = 0;
318  temp1 = temp1->Next;
319  if(!temp1) temp1 = list;
320  }
321  if(u_cur==0) {
322  temp1->intersect = 2;
323  temp1->isInside = 1;
324  temp1->u = u_cur;
325  temp1->x = x;
326  temp1->y = y;
327  temp1->z = z;
328  return;
329  }
330 
331  /* when u2 != 0 and u2 !=1, can decide if one end of the point is outside depending on inbound value */
332  if(u2 != 0 && u2 != 1) {
333  if(inbound == 1) { /* goes outside, then temp1->Next is an outside point */
334  /* find the next non-intersect point */
335  temp2 = temp1->Next;
336  if(!temp2) temp2 = list;
337  while(temp2->intersect) {
338  temp2=temp2->Next;
339  if(!temp2) temp2 = list;
340  }
341 
342  temp2->isInside = 0;
343  }
344  else if(inbound ==2) { /* goes inside, then temp1 is an outside point */
345  temp1->isInside = 0;
346  }
347  }
348 
349  temp2 = temp1->Next;
350  while ( temp2 ) {
351  if( temp2->intersect == 1 ) {
352  if( temp2->u > u_cur ) {
353  break;
354  }
355  }
356  else
357  break;
358  temp1 = temp2;
359  temp2 = temp2->Next;
360  }
361 
362  /* assign value */
363  temp = getNext();
364  temp->x = x;
365  temp->y = y;
366  temp->z = z;
367  temp->u = u_cur;
368  temp->intersect = 1;
369  temp->inbound = inbound;
370  temp->isInside = 1;
371  temp->initialized = 1;
372  temp1->Next = temp;
373  temp->Next = temp2;
374 
375 }
376 
377 double gridArea(struct Node *grid) {
378  double x[20], y[20], z[20];
379  struct Node *temp=NULL;
380  double area;
381  int n;
382 
383  temp = grid;
384  n = 0;
385  while( temp ) {
386  x[n] = temp->x;
387  y[n] = temp->y;
388  z[n] = temp->z;
389  n++;
390  temp = temp->Next;
391  }
392 
393  area = great_circle_area(n, x, y, z);
394 
395  return area;
396 
397 }
398 
399 int isIntersect(struct Node node) {
400 
401  return node.intersect;
402 
403 }
404 
405 
406 int getInbound( struct Node node )
407 {
408  return node.inbound;
409 }
410 
411 struct Node *getLast(struct Node *list)
412 {
413  struct Node *temp1;
414 
415  temp1 = list;
416  if( temp1 ) {
417  while( temp1->Next ) {
418  temp1 = temp1->Next;
419  }
420  }
421 
422  return temp1;
423 }
424 
425 
426 int getFirstInbound( struct Node *list, struct Node *nodeOut)
427 {
428  struct Node *temp=NULL;
429 
430  temp=list;
431 
432  while(temp) {
433  if( temp->inbound == 2 ) {
434  copyNode(nodeOut, *temp);
435  return 1;
436  }
437  temp=temp->Next;
438  }
439 
440  return 0;
441 }
442 
443 void getCoordinate(struct Node node, double *x, double *y, double *z)
444 {
445 
446 
447  *x = node.x;
448  *y = node.y;
449  *z = node.z;
450 
451 }
452 
453 void getCoordinates(struct Node *node, double *p)
454 {
455 
456 
457  p[0] = node->x;
458  p[1] = node->y;
459  p[2] = node->z;
460 
461 }
462 
463 void setCoordinate(struct Node *node, double x, double y, double z)
464 {
465 
466 
467  node->x = x;
468  node->y = y;
469  node->z = z;
470 
471 }
472 
473 /* set inbound value for the points in interList that has inbound =0,
474  this will also set some inbound value of the points in list1
475 */
476 
477 void setInbound(struct Node *interList, struct Node *list)
478 {
479 
480  struct Node *temp1=NULL, *temp=NULL;
481  struct Node *temp1_prev=NULL, *temp1_next=NULL;
482  int prev_is_inside, next_is_inside;
483 
484  /* for each point in interList, search through list to decide the inbound value the interList point */
485  /* For each inbound point, the prev node should be outside and the next is inside. */
486  if(length(interList) == 0) return;
487 
488  temp = interList;
489 
490  while(temp) {
491  if( !temp->inbound) {
492  /* search in grid1 to find the prev and next point of temp, when prev point is outside and next point is inside
493  inbound = 2, else inbound = 1*/
494  temp1 = list;
495  temp1_prev = NULL;
496  temp1_next = NULL;
497  while(temp1) {
498  if(sameNode(*temp1, *temp)) {
499  if(!temp1_prev) temp1_prev = getLast(list);
500  temp1_next = temp1->Next;
501  if(!temp1_next) temp1_next = list;
502  break;
503  }
504  temp1_prev = temp1;
505  temp1 = temp1->Next;
506  }
507  if(!temp1_next) error_handler("Error from create_xgrid.c: temp is not in list1");
508  if( temp1_prev->isInside == 0 && temp1_next->isInside == 1)
509  temp->inbound = 2; /* go inside */
510  else
511  temp->inbound = 1;
512  }
513  temp=temp->Next;
514  }
515 }
516 
517 int isInside(struct Node *node) {
518 
519  if(node->isInside == -1) error_handler("Error from mosaic_util.c: node->isInside is not set");
520  return(node->isInside);
521 
522 }
523 
524 /* #define debug_test_create_xgrid */
525 
526 /* check if node is inside polygon list or not */
527 int insidePolygon( struct Node *node, struct Node *list)
528 {
529  int is_inside;
530  double pnt0[3], pnt1[3], pnt2[3];
531  double anglesum;
532  struct Node *p1=NULL, *p2=NULL;
533 
534  anglesum = 0;
535 
536  pnt0[0] = node->x;
537  pnt0[1] = node->y;
538  pnt0[2] = node->z;
539 
540  p1 = list;
541  p2 = list->Next;
542  is_inside = 0;
543 
544 
545  while(p1) {
546  pnt1[0] = p1->x;
547  pnt1[1] = p1->y;
548  pnt1[2] = p1->z;
549  pnt2[0] = p2->x;
550  pnt2[1] = p2->y;
551  pnt2[2] = p2->z;
552  if( samePoint(pnt0[0], pnt0[1], pnt0[2], pnt1[0], pnt1[1], pnt1[2]) ){
553  return 1;
554  }
555  anglesum += spherical_angle(pnt0, pnt2, pnt1);
556  p1 = p1->Next;
557  p2 = p2->Next;
558  if(p2==NULL){
559  p2 = list;
560  }
561  }
562 
563  if( fabs(anglesum - 2*M_PI) < EPSLN8 ){
564  is_inside = 1;
565  }
566  else{
567  is_inside = 0;
568  }
569 
570  return is_inside;
571 
572 }
real(r8_kind), dimension(:,:), allocatable area
area of each grid box