FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
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
32struct Node *nodeList=NULL;
33int curListPos=0;
34
35void 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
45struct 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
63void 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
77void 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
116int 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
173int 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 */
190int 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
199int 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
208void 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
215struct 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
233struct Node *getNextNode(struct Node *list)
234{
235 return list->Next;
236}
237
238void 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
252void 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
268int 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*/
295void 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
377double 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
399int isIntersect(struct Node node) {
400
401 return node.intersect;
402
403}
404
405
406int getInbound( struct Node node )
407{
408 return node.inbound;
409}
410
411struct 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
426int 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
443void 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
453void 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
463void 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
477void 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
517int 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 */
527int 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