source: trunk/anuga_core/source/anuga/utilities/quad_tree.c @ 9072

Last change on this file since 9072 was 8691, checked in by steve, 12 years ago

Adding in the new c files

File size: 12.8 KB
Line 
1#include "quad_tree.h"
2
3// **************** UTILITIES ***********************
4
5static void *emalloc(size_t amt,char * location)
6{
7    void *v = malloc(amt); 
8    if(!v){
9        fprintf(stderr, "out of mem in quad_tree: %s\n",location);
10        exit(EXIT_FAILURE);
11    }
12    return v;
13};
14
15double dot_points(double p1x,double p1y,double p2x,double p2y)
16{
17   
18    return p1x * p2x + p1y * p2y;
19   
20};
21
22// ***************************************************
23
24// ******************* TRIANGLE **********************
25
26triangle * new_triangle(int index,double x1,double y1,double x2,double y2,double x3,double y3)
27{
28
29        triangle * T = emalloc(sizeof(triangle),"new_triangle"); 
30         
31        T->index = index;
32        T->x1 = x1; T->x2 = x2; T->x3 = x3;
33    T->y1 = y1; T->y2 = y2; T->y3 = y3;
34    T->next = NULL;
35
36    // Calculate the normals
37    // normal for vector from x1->x2
38    double nx_temp,ny_temp,dot_temp;
39    ny_temp = ( T->x2 - T->x1 );
40    nx_temp = -( T->y2 - T->y1 );
41    dot_temp = dot_points(nx_temp, ny_temp, nx_temp, ny_temp);
42    T->nx3 = nx_temp / sqrt(dot_temp);
43    T->ny3 = ny_temp / sqrt(dot_temp);
44    if( dot_points(T->nx3, T->ny3, T->x3 - T->x2, T->y3 - T->y2) > 0 ){
45        T->nx3 = -T->nx3;
46        T->ny3 = -T->ny3;
47    }
48    // normal for vector from x2->x3
49    ny_temp = ( T->x3 - T->x2 );
50    nx_temp = -(T->y3 - T ->y2 );
51    dot_temp = dot_points(nx_temp, ny_temp, nx_temp, ny_temp);
52    T->nx1 = nx_temp / sqrt(dot_temp);
53    T->ny1 = ny_temp / sqrt(dot_temp);
54    if( dot_points(T->nx1, T->ny1, T->x1 - T->x3, T->y1 - T->y3) > 0 ){
55        T->nx1 = -T->nx1;
56        T->ny1 = -T->ny1;
57    }
58    // normal for vector from x3->x1
59    ny_temp = ( T->x1 - T->x3 );
60    nx_temp = -( T->y1 - T->y3 );
61    dot_temp = dot_points(nx_temp, ny_temp, nx_temp, ny_temp);
62    T->nx2 = nx_temp / sqrt(dot_temp);
63    T->ny2 = ny_temp / sqrt(dot_temp);
64    if( dot_points(T->nx2, T->ny2, T->x2 - T->x1, T->y2 - T->y1) > 0 ){
65        T->nx2 = -T->nx2;
66        T->ny2 = -T->ny2;
67    }
68
69    return T;
70};
71
72void delete_triangle_list(triangle * T)
73{
74        while (T != NULL){
75     triangle * next = T->next;
76           free(T);
77           T = NULL;
78     T = next;
79  }
80};
81
82double * calculate_sigma(triangle * T,double x,double y)
83{
84
85        double  * ret_sigma = malloc(3 * sizeof(double));
86        ret_sigma[0] = dot_points(x - T->x2, y - T->y2, T->nx1, T->ny1)/
87                                        dot_points(T->x1 - T->x2, T->y1 - T->y2, T->nx1, T->ny1);
88        ret_sigma[1] = dot_points(x - T->x3, y - T->y3, T->nx2, T->ny2)/
89                                        dot_points(T->x2 - T->x3, T->y2 - T->y3, T->nx2, T->ny2);
90        ret_sigma[2] = dot_points(x - T->x1, y - T->y1, T->nx3, T->ny3)/
91                                        dot_points(T->x3 - T->x1, T->y3 - T->y1, T->nx3, T->ny3);
92        return ret_sigma;                               
93};
94
95double dist(double x,
96            double y) {
97 
98  return sqrt(x*x + y*y);
99}
100
101int __point_on_line(double x, double y,
102                    double x0, double y0,
103                    double x1, double y1,
104                    double rtol,
105                    double atol) {
106  /*Determine whether a point is on a line segment
107
108    Input: x, y, x0, x0, x1, y1: where
109        point is given by x, y
110        line is given by (x0, y0) and (x1, y1)
111
112  */
113
114  double a0, a1, a_normal0, a_normal1, b0, b1, len_a, len_b;
115  double nominator, denominator;
116  int is_parallel;
117
118  a0 = x - x0;
119  a1 = y - y0;
120
121  a_normal0 = a1;
122  a_normal1 = -a0;
123
124  b0 = x1 - x0;
125  b1 = y1 - y0;
126
127  nominator = fabs(a_normal0*b0 + a_normal1*b1);
128  denominator = b0*b0 + b1*b1;
129 
130  // Determine if line is parallel to point vector up to a tolerance
131  is_parallel = 0;
132  if (denominator == 0.0) {
133    // Use absolute tolerance
134    if (nominator <= atol) {
135      is_parallel = 1;
136    }
137  } else {
138    // Denominator is positive - use relative tolerance
139    if (nominator/denominator <= rtol) {
140      is_parallel = 1;
141    }   
142  }
143   
144  if (is_parallel) {
145    // Point is somewhere on the infinite extension of the line
146    // subject to specified absolute tolerance
147
148    len_a = dist(a0, a1); //sqrt(a0*a0 + a1*a1);
149    len_b = dist(b0, b1); //sqrt(b0*b0 + b1*b1);
150
151    if (a0*b0 + a1*b1 >= 0 && len_a <= len_b) {
152      return 1;
153    } else {
154      return 0;
155    }
156  } else {
157    return 0;
158  }
159};
160
161int __is_inside_triangle(double* point,
162                         double* triangle,
163                         int closed,
164                         double rtol,
165                         double a_tol) {
166                         
167  double vx, vy, v0x, v0y, v1x, v1y;
168  double a00, a10, a01, a11, b0, b1;
169  double denom, alpha, beta;
170 
171  double x, y; // Point coordinates
172  int i, j, res;
173
174  x = point[0];
175  y = point[1];
176 
177  // Quickly reject points that are clearly outside
178  if ((x < triangle[0]) && 
179      (x < triangle[2]) && 
180      (x < triangle[4])) return 0;       
181     
182  if ((x > triangle[0]) && 
183      (x > triangle[2]) && 
184      (x > triangle[4])) return 0;             
185 
186  if ((y < triangle[1]) && 
187      (y < triangle[3]) && 
188      (y < triangle[5])) return 0;       
189     
190  if ((y > triangle[1]) && 
191      (y > triangle[3]) && 
192      (y > triangle[5])) return 0;             
193 
194 
195  // v0 = C-A
196  v0x = triangle[4]-triangle[0]; 
197  v0y = triangle[5]-triangle[1];
198 
199  // v1 = B-A   
200  v1x = triangle[2]-triangle[0]; 
201  v1y = triangle[3]-triangle[1];
202
203  // First check if point lies wholly inside triangle
204  a00 = v0x*v0x + v0y*v0y; // innerproduct(v0, v0)
205  a01 = v0x*v1x + v0y*v1y; // innerproduct(v0, v1)
206  a10 = a01;               // innerproduct(v1, v0)
207  a11 = v1x*v1x + v1y*v1y; // innerproduct(v1, v1)
208   
209  denom = a11*a00 - a01*a10;
210
211  if (fabs(denom) > 0.0) {
212    // v = point-A 
213    vx = x - triangle[0]; 
214    vy = y - triangle[1];     
215   
216    b0 = v0x*vx + v0y*vy; // innerproduct(v0, v)       
217    b1 = v1x*vx + v1y*vy; // innerproduct(v1, v)           
218   
219    alpha = (b0*a11 - b1*a01)/denom;
220    beta = (b1*a00 - b0*a10)/denom;       
221   
222    if ((alpha > 0.0) && (beta > 0.0) && (alpha+beta < 1.0)) return 1;
223  }
224
225  if (closed) {
226    // Check if point lies on one of the edges
227       
228    for (i=0; i<3; i++) {
229      j = (i+1) % 3; // Circular index into triangle array
230
231      res = __point_on_line(x, y,
232                            triangle[2*i], triangle[2*i+1], 
233                            triangle[2*j], triangle[2*j+1],                         
234                            rtol, a_tol);
235      if (res) return 1;
236    }
237  };
238  // Default return if point is outside triangle                         
239  return 0;                                             
240}                                                       
241
242int triangle_contains_point(triangle * T,double pointx,double pointy)
243{
244   
245//    double v0x,v0y,v1x,v1y,v2x,v2y,dot00,dot01,dot02,dot11,dot12,invDenom,u,v;
246//   
247//    v0x = T->x3 - T->x1;
248//    v0y = T->y3 - T->y1;
249//    v1x = T->x2 - T->x1;
250//    v1y = T->y2 - T->y1;
251//    v2x = pointx - T->x1;
252//    v2y = pointy - T->y1;
253//   
254//    dot00 = dot_points(v0x, v0y, v0x, v0y);
255//    dot01 = dot_points(v0x, v0y, v1x, v1y);
256//    dot02 = dot_points(v0x, v0y, v2x, v2y);
257//    dot11 = dot_points(v1x, v1y, v1x, v1y);
258//    dot12 = dot_points(v1x, v1y, v2x, v2y);
259//   
260//    invDenom = 1/(dot00*dot11-dot01*dot01);
261//    u=(dot11 * dot02 - dot01 * dot12) * invDenom;
262//    v=(dot00 * dot12 - dot01 * dot02) * invDenom;
263//   
264//    if( u>=0 && v>=0 && v+u<1) return 1;
265//   
266//    else return 0;
267      double tri[6];
268      tri[0]=T->x1; tri[1]=T->y1; tri[2]=T->x2; tri[3]=T->y2; tri[4]=T->x3; tri[5]=T->y3;
269      double point[2];
270      point[0] = pointx; point[1] = pointy;
271      double rtol=1.0e-12;
272      double a_tol=1.0e-12;
273      int closed = 1;
274
275      return __is_inside_triangle(point,
276                         tri,
277                         closed,
278                         rtol,
279                         a_tol); 
280
281
282};
283
284
285
286// ***************************************************
287
288// ***************** quad_tree *********************
289
290quad_tree * new_quad_tree(double xmin, double xmax, double ymin, double ymax)
291{
292
293        quad_tree * ret = emalloc(sizeof(quad_tree),"new_quad_tree");
294        ret -> xmin = xmin; ret-> xmax = xmax; 
295        ret -> ymin = ymin; ret -> ymax = ymax;
296        ret -> parent = NULL;
297        ret -> q[0] = NULL; ret -> q[1] = NULL; ret -> q[2] = NULL; ret -> q[3] = NULL;
298        ret -> leaves = NULL;
299        ret -> end_leaves = NULL;
300  ret -> count = 0;
301        return ret; 
302
303};
304
305void delete_quad_tree(quad_tree * quadtree)
306{
307
308  quad_tree_ll * nodelist = new_quad_tree_ll(quadtree,0);
309  quad_tree_ll * last = nodelist;
310  quad_tree_ll * temp;
311  int i;
312
313  while(nodelist !=NULL){
314     
315      quadtree=nodelist->tree;
316      // if children have been added, add to the linked list
317
318      if (quadtree->q[0]!=NULL){
319          for (i=0;i<4;i++){
320              quad_tree_ll * child = new_quad_tree_ll(quadtree->q[i],0);
321              last->next=child;
322              last=child;
323          }
324      }
325     
326      if (quadtree->leaves!=NULL){
327          delete_triangle_list(quadtree->leaves);
328      }
329
330      free(quadtree);
331      quadtree=NULL;
332
333      temp = nodelist;
334      nodelist=nodelist->next;
335      free(temp);
336  }
337
338};
339
340void quad_tree_make_children(quad_tree *node){
341
342  double xmid = (node->xmin+node->xmax)/2;
343  double ymid = (node->ymin+node->ymax)/2;
344  double width = (node->xmax-node->xmin);
345  double height = (node->ymax-node->ymin);
346  // add quads 1-4
347  // include border expansion
348  double border=0.55;
349  node->q[0] = new_quad_tree(node->xmax-width*border,node->xmax,node->ymax-height*border,node->ymax);
350  node->q[0]->parent = node; 
351 
352  node->q[1] = new_quad_tree(node->xmin,node->xmin+width*border,node->ymax-height*border,node->ymax);
353  node->q[1]->parent = node; 
354 
355  node->q[2] = new_quad_tree(node->xmin,node->xmin+width*border,node->ymin,node->ymin+height*border);
356  node->q[2]->parent = node; 
357 
358  node->q[3] = new_quad_tree(node->xmax-width*border,node->xmax,node->ymin,node->ymin+height*border);
359  node->q[3]->parent = node; 
360
361}
362
363void quad_tree_add_triangle_to_list(quad_tree *node,triangle *T){
364
365  if (node->leaves == NULL){
366    // no current leaves
367    node->leaves = T;
368    node->end_leaves = T;
369  } else {
370    node->end_leaves->next = T;
371    node->end_leaves = T;
372  }
373
374}
375
376void quad_tree_insert_triangle(quad_tree *node,triangle *T)
377{
378       
379        // find the quadrant of the current node's extents in which the
380        // point lies (zero if intersects center of extents axes).
381
382        int quad = trivial_contain_split(node,T);
383
384  // always increase point count, as storing the total in tree below
385  node->count+=1;
386
387        if (quad != 0){
388                // if current node has no children yet, split:
389                if(node->q[0] == NULL){
390                       
391                        quad_tree_make_children(node); 
392                       
393            }
394            // insert triangle into node corresponding to given quadrant
395                quad_tree_insert_triangle(node->q[quad-1],T);
396                return;
397               
398        }
399        // if triangle intersects the center axes of the node's extents, insert
400        // the triangle here
401        quad_tree_add_triangle_to_list(node,T);
402
403};
404
405
406int trivial_contain_split(quad_tree *node, triangle *T){
407
408        int p1 = trivial_contain_split_point(node,T->x1,T->y1);
409        int p2 = trivial_contain_split_point(node,T->x2,T->y2);
410        int p3 = trivial_contain_split_point(node,T->x3,T->y3);
411        if(p1 == p2 && p2 == p3){
412                return p1;
413        }
414        return 0;
415};
416
417int trivial_contain_split_point(quad_tree *node, double xp,double yp)
418{
419
420        double midx = (node->xmin+node->xmax)/2;
421        double midy = (node->ymin+node->ymax)/2;
422
423        int ret=0;
424       
425        if (midx < xp){
426                // quad 1 or 4
427                if (midy < yp){
428                        ret = 1;
429                } else if (midy > yp){
430                        ret = 4;
431                }
432        } else if (midx > xp){
433                //quad 2 or 3
434                if (midy < yp){
435                        ret = 2;
436                } else if (midy > yp){
437                        ret = 3;
438                }
439        }
440        return ret;
441};
442
443triangle * search_triangles_of_quad_tree(quad_tree * node,double xp,double yp){
444       
445    triangle * T = node->leaves;
446
447    while(T != NULL){
448        if(triangle_contains_point(T,xp,yp)){
449            return T; // Triangle contains point so return
450        }
451        T = T->next;
452    }
453        return T; // should be NULL if this is reached
454};
455
456// Searches the quad tree starting at 'cur_quad_tree' for the
457// point, returning the triangle that contains it, or NULL
458// if no triangle is found.
459triangle * search(quad_tree * node, double xp, double yp){
460
461    triangle * return_T = NULL;
462
463    if(node->leaves!=NULL)
464    {
465        return_T = search_triangles_of_quad_tree(node,xp,yp);
466    }
467    if(return_T != NULL) return return_T;
468           
469    else
470    {
471        if(node->q[0]!=NULL) // look for child to search
472        {
473            //find correct quadrant to search
474            int quad = trivial_contain_split_point(node,xp,yp);
475           
476            if (quad!=0)
477            {
478            return_T = search(node->q[quad-1],xp,yp); // search child
479            }
480
481        return return_T; // return NULL pointer as no triangle
482        }
483        }
484        return return_T; // should not be reached
485};
486
487int quad_tree_node_count(quad_tree * tree)
488{
489  int node_count = 1;
490  if (tree->q[0]!=NULL){
491      int i;
492      for(i=0;i<4;i++){
493        node_count+=quad_tree_node_count(tree->q[i]);
494      }
495  }
496  return node_count;
497};
498
499// ***************************************************
500
501// ***************** quad_tree_ll *******************
502
503quad_tree_ll * new_quad_tree_ll(quad_tree * start,int index){
504    quad_tree_ll * list = malloc(sizeof(quad_tree_ll));
505    list->tree = start;
506    list->next = NULL;
507    list->index = index;
508    return list;
509}
510
511// ***************************************************
512
513// ***************** queue_ll *******************
514
515queue_ll * new_queue_ll(int node){
516    queue_ll * list = malloc(sizeof(queue_ll));
517    list->node=node;
518    list->next = NULL;
519    return list;
520}
521
522// ***************************************************
Note: See TracBrowser for help on using the repository browser.