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