vert_tree.c

Go to the documentation of this file.
00001 /*                     V E R T _ T R E E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2002-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup vtree */
00023 /*@{*/
00024 /** @file vert_tree.c
00025  * @brief
00026  * Routines to manage a binary search tree of vertices. 
00027  *
00028  * The actual vertices are stored in an array
00029  * for convenient use by routines such as "mk_bot". 
00030  * The binary search tree stores indices into the array.
00031  *
00032  *  @author
00033  *      John R. Anderson
00034  *
00035  * @par  Source -
00036  *      The U. S. Army Research Laboratory
00037  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00038  */
00039 
00040 
00041 #ifndef lint
00042 static const char bn_RCSvert_tree[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/vert_tree.c,v 14.13 2006/09/07 01:19:17 lbutler Exp $ (ARL)";
00043 #endif
00044 
00045 #include "common.h"
00046 
00047 #include <stdlib.h>
00048 #include <stdio.h>
00049 #include <math.h>
00050 #ifdef HAVE_STRING_H
00051 #  include <string.h>
00052 #else
00053 #  include <strings.h>
00054 #endif
00055 #include <ctype.h>
00056 #include <errno.h>
00057 
00058 #include "machine.h"
00059 #include "vmath.h"
00060 #include "raytrace.h"
00061 
00062 
00063 /**
00064  * Structure to make vertex searching fast.
00065  *
00066  * Each leaf represents a vertex, and has an index into 
00067  *   the vertices array ("the_array")
00068  *
00069  * Each node is a cutting plane at the "cut_val" on 
00070  *   the "coord" (0, 1, or 2) axis.
00071  *
00072  * All vertices with "coord" value less than the "cut_val" are in the "lower"
00073  * subtree, others are in the "higher".
00074  */
00075 union vert_tree {
00076         char type;              /* type - leaf or node */
00077         struct vert_leaf {
00078                 char type;
00079                 int index;      /* index into the array */
00080         } vleaf;
00081         struct vert_node {
00082                 char type;
00083                 double cut_val; /* cutting value */
00084                 int coord;      /* cutting coordinate */
00085                 union vert_tree *higher, *lower;        /* subtrees */
00086         } vnode;
00087 };
00088 
00089 /* types for the above "vert_tree" */
00090 #define VERT_LEAF       'l'
00091 #define VERT_NODE       'n'
00092 
00093 
00094 /**             C R E A T E _ V E R T _ T R E E
00095  *@brief
00096  *      routine to create a vertex tree.
00097  *
00098  *      Possible refinements include specifying an initial size
00099  */
00100 struct vert_root *
00101 create_vert_tree()
00102 {
00103         struct vert_root *tree;
00104 
00105         tree = (struct vert_root *)bu_calloc( 1, sizeof( struct vert_root ), "vert_tree_root" );
00106         tree->magic = VERT_TREE_MAGIC;
00107         tree->tree_type = TREE_TYPE_VERTS;
00108         tree->the_tree = (union vert_tree *)NULL;
00109         tree->curr_vert = 0;
00110         tree->max_vert = VERT_BLOCK;
00111         tree->the_array = (fastf_t *)bu_malloc( tree->max_vert * 3 * sizeof( fastf_t ), "vert tree array" );
00112 
00113         return( tree );
00114 }
00115 
00116 /**             C R E A T E _ V E R T _ T R E E _ W _ N O R M S
00117  *@brief
00118  *      routine to create a vertex tree.
00119  *
00120  *      Possible refinements include specifying an initial size
00121  */
00122 struct vert_root *
00123 create_vert_tree_w_norms()
00124 {
00125         struct vert_root *tree;
00126 
00127         tree = (struct vert_root *)bu_calloc( 1, sizeof( struct vert_root ), "vert_tree_root" );
00128         tree->magic = VERT_TREE_MAGIC;
00129         tree->tree_type = TREE_TYPE_VERTS_AND_NORMS;
00130         tree->the_tree = (union vert_tree *)NULL;
00131         tree->curr_vert = 0;
00132         tree->max_vert = VERT_BLOCK;
00133         tree->the_array = (fastf_t *)bu_malloc( tree->max_vert * 6 * sizeof( fastf_t ), "vert tree array" );
00134 
00135         return( tree );
00136 }
00137 
00138 /**             C L E A N _ V E R T_ T R E E _ R E C U R S E
00139  *@brief
00140  *      static recursion routine used by "clean_vert_tree"
00141  */
00142 static void
00143 clean_vert_tree_recurse( union vert_tree *ptr )
00144 {
00145         if( ptr->type == VERT_NODE ) {
00146                 clean_vert_tree_recurse( ptr->vnode.higher );
00147                 clean_vert_tree_recurse( ptr->vnode.lower );
00148         }
00149 
00150         bu_free( (char *)ptr, "vert_tree" );
00151 
00152 }
00153 
00154 /**             C L E A N _ V E R T _ T R E E
00155  *@brief
00156  *      Routine to free the binary search tree and reset the current number of vertices.
00157  *      The vertex array is left untouched, for re-use later.
00158  */
00159 void
00160 clean_vert_tree( struct vert_root *tree_root )
00161 {
00162         BN_CK_VERT_TREE( tree_root );
00163 
00164         if( !tree_root->the_tree ) return;
00165 
00166         clean_vert_tree_recurse( tree_root->the_tree );
00167         tree_root->the_tree = (union vert_tree *)NULL;
00168         tree_root->curr_vert = 0;
00169 }
00170 
00171 
00172 /**             F R E E _ V E R T_ T R E E_ R E C U R S E
00173  *@brief
00174  *      Static recursive routine used by "free_vert_tree"
00175  */
00176 static void
00177 free_vert_tree_recurse( union vert_tree *ptr )
00178 {
00179         if( ptr->type == VERT_NODE ) {
00180                 free_vert_tree_recurse( ptr->vnode.higher );
00181                 free_vert_tree_recurse( ptr->vnode.lower );
00182         }
00183 
00184         bu_free( (char *)ptr, "vert_tree" );
00185 
00186 }
00187 
00188 /**             F R E E _ V E R T_ T R E E
00189  *@brief
00190  *      Routine to free a vertex tree and all associated dynamic memory
00191  */
00192 void
00193 free_vert_tree( struct vert_root *vert_root )
00194 {
00195         union vert_tree *ptr;
00196 
00197         if( !vert_root )
00198                 return;
00199 
00200         BN_CK_VERT_TREE( vert_root );
00201 
00202         ptr = vert_root->the_tree;
00203         if( !ptr )
00204                 return;
00205 
00206         free_vert_tree_recurse( ptr );
00207 
00208         if( vert_root->the_array ) {
00209                 bu_free( (char *)vert_root->the_array, "vertex array" );
00210         }
00211 
00212         vert_root->the_tree = (union vert_tree *)NULL;
00213         vert_root->the_array = (fastf_t *)NULL;
00214         vert_root->curr_vert = 0;
00215         vert_root->max_vert = 0;
00216 }
00217 
00218 /**             A D D _ V E R T
00219  *@brief
00220  *      Routine to add a vertex to the current list of part vertices.
00221  *      The array is re-alloc'd if needed.
00222  *      Returns index into the array of vertices where this vertex is stored
00223  */
00224 int
00225 Add_vert( double x, double y, double z, struct vert_root *vert_root, fastf_t local_tol_sq )
00226 {
00227         union vert_tree *ptr, *prev=NULL, *new_leaf, *new_node;
00228         vect_t diff;
00229         vect_t vertex;
00230 
00231         BN_CK_VERT_TREE( vert_root );
00232 
00233         if( vert_root->tree_type != TREE_TYPE_VERTS ) {
00234                 bu_bomb( "Error: Add_vert() called for a tree containing vertices and normals\n" );
00235         }
00236 
00237         VSET( vertex, x, y, z );
00238 
00239         /* look for this vertex already in the list */
00240         ptr = vert_root->the_tree;
00241         while( ptr ) {
00242                 if( ptr->type == VERT_NODE ) {
00243                         prev = ptr;
00244                         if( vertex[ptr->vnode.coord] >= ptr->vnode.cut_val ) {
00245                                 ptr = ptr->vnode.higher;
00246                         } else {
00247                                 ptr = ptr->vnode.lower;
00248                         }
00249                 } else {
00250                         int ij;
00251 
00252                         ij = ptr->vleaf.index*3;
00253                         diff[0] = fabs( vertex[0] - vert_root->the_array[ij] );
00254                         diff[1] = fabs( vertex[1] - vert_root->the_array[ij+1] );
00255                         diff[2] = fabs( vertex[2] - vert_root->the_array[ij+2] );
00256                         if( (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]) <= local_tol_sq ) {
00257                                 /* close enough, use this vertex again */
00258                                 return( ptr->vleaf.index );
00259                         }
00260                         break;
00261                 }
00262         }
00263 
00264         /* add this vertex to the list */
00265         if( vert_root->curr_vert >= vert_root->max_vert ) {
00266                 /* allocate more memory for vertices */
00267                 vert_root->max_vert += VERT_BLOCK;
00268 
00269                 vert_root->the_array = (fastf_t *)bu_realloc( vert_root->the_array, sizeof( fastf_t ) * vert_root->max_vert * 3,
00270                                                     "vert_root->the_array" );
00271         }
00272 
00273         VMOVE( &vert_root->the_array[vert_root->curr_vert*3], vertex );
00274 
00275         /* add to the tree also */
00276         new_leaf = (union vert_tree *)bu_malloc( sizeof( union vert_tree ), "new_leaf" );
00277         new_leaf->vleaf.type = VERT_LEAF;
00278         new_leaf->vleaf.index = vert_root->curr_vert++;
00279         if( !vert_root->the_tree ) {
00280                 /* first vertex, it becomes the root */
00281                 vert_root->the_tree = new_leaf;
00282         } else if( ptr && ptr->type == VERT_LEAF ) {
00283                 /* search above ended at a leaf, need to add a node above this leaf and the new leaf */
00284                 new_node = (union vert_tree *)bu_malloc( sizeof( union vert_tree ), "new_node" );
00285                 new_node->vnode.type = VERT_NODE;
00286 
00287                 /* select the cutting coord based on the biggest difference */
00288                 if( diff[0] >= diff[1] && diff[0] >= diff[2] ) {
00289                         new_node->vnode.coord = 0;
00290                 } else if( diff[1] >= diff[2] && diff[1] >= diff[0] ) {
00291                         new_node->vnode.coord = 1;
00292                 } else if( diff[2] >= diff[1] && diff[2] >= diff[0] ) {
00293                         new_node->vnode.coord = 2;
00294                 }
00295 
00296                 /* set the cut value to the mid value between the two vertices */
00297                 new_node->vnode.cut_val = (vertex[new_node->vnode.coord] +
00298                                            vert_root->the_array[ptr->vleaf.index * 3 + new_node->vnode.coord]) * 0.5;
00299 
00300                 /* set the node "lower" nad "higher" pointers */
00301                 if( vertex[new_node->vnode.coord] >=
00302                     vert_root->the_array[ptr->vleaf.index * 3 + new_node->vnode.coord] ) {
00303                         new_node->vnode.higher = new_leaf;
00304                         new_node->vnode.lower = ptr;
00305                 } else {
00306                         new_node->vnode.higher = ptr;
00307                         new_node->vnode.lower = new_leaf;
00308                 }
00309 
00310                 if( ptr == vert_root->the_tree ) {
00311                         /* if the above search ended at the root, redefine the root */
00312                         vert_root->the_tree =  new_node;
00313                 } else {
00314                         /* set the previous node to point to our new one */
00315                         if( prev->vnode.higher == ptr ) {
00316                                 prev->vnode.higher = new_node;
00317                         } else {
00318                                 prev->vnode.lower = new_node;
00319                         }
00320                 }
00321         } else if( ptr && ptr->type == VERT_NODE ) {
00322                 /* above search ended at a node, just add the new leaf */
00323                 prev = ptr;
00324                 if( vertex[prev->vnode.coord] >= prev->vnode.cut_val ) {
00325                         if( prev->vnode.higher ) {
00326                             bu_bomb("higher vertex node already exists in Add_vert()?\n");
00327                         }
00328                         prev->vnode.higher = new_leaf;
00329                 } else {
00330                         if( prev->vnode.lower ) {
00331                             bu_bomb("lower vertex node already exists in Add_vert()?\n");
00332                         }
00333                         prev->vnode.lower = new_leaf;
00334                 }
00335         } else {
00336                 fprintf( stderr, "*********ERROR********\n" );
00337         }
00338 
00339         /* return the index into the vertex array */
00340         return( new_leaf->vleaf.index );
00341 }
00342 
00343 /**             A D D _ V E R T _ A N D _ N O R M
00344  *@brief
00345  *      Routine to add a vertex and a normal to the current list of part vertices.
00346  *      The array is re-alloc'd if needed.
00347  *      Returns index into the array of vertices where this vertex and normal is stored
00348  */
00349 int
00350 Add_vert_and_norm( double x, double y, double z, double nx, double ny, double nz, struct vert_root *vert_root, fastf_t local_tol_sq )
00351 {
00352         union vert_tree *ptr, *prev=NULL, *new_leaf, *new_node;
00353         fastf_t diff[6];
00354         fastf_t vertex[6];
00355         double d1_sq=0.0, d2_sq=0.0;
00356 
00357         BN_CK_VERT_TREE( vert_root );
00358 
00359         if( vert_root->tree_type != TREE_TYPE_VERTS_AND_NORMS ) {
00360                 bu_bomb( "Error: Add_vert_and_norm() called for a tree containing just vertices\n" );
00361         }
00362 
00363         VSET( vertex, x, y, z );
00364         VSET( &vertex[3], nx, ny, nz );
00365 
00366         /* look for this vertex and normal already in the list */
00367         ptr = vert_root->the_tree;
00368         while( ptr ) {
00369                 int i;
00370 
00371                 if( ptr->type == VERT_NODE ) {
00372                         prev = ptr;
00373                         if( vertex[ptr->vnode.coord] >= ptr->vnode.cut_val ) {
00374                                 ptr = ptr->vnode.higher;
00375                         } else {
00376                                 ptr = ptr->vnode.lower;
00377                         }
00378                 } else {
00379                         int ij;
00380 
00381                         ij = ptr->vleaf.index*6;
00382                         for( i=0 ; i<6 ; i++ ) {
00383                                 diff[i] = fabs( vertex[i] - vert_root->the_array[ij+i] );
00384                         }
00385                         d1_sq = VDOT( diff, diff );
00386                         d2_sq = VDOT( &diff[3], &diff[3] );
00387                         if( d1_sq <= local_tol_sq && d2_sq <= 0.0001 ) {
00388                                 /* close enough, use this vertex and normal again */
00389                                 return( ptr->vleaf.index );
00390                         }
00391                         break;
00392                 }
00393         }
00394 
00395         /* add this vertex and normal to the list */
00396         if( vert_root->curr_vert >= vert_root->max_vert ) {
00397                 /* allocate more memory for vertices */
00398                 vert_root->max_vert += VERT_BLOCK;
00399 
00400                 vert_root->the_array = (fastf_t *)bu_realloc( vert_root->the_array,
00401                                          sizeof( fastf_t ) * vert_root->max_vert * 6,
00402                                          "vert_root->the_array" );
00403         }
00404 
00405         VMOVE( &vert_root->the_array[vert_root->curr_vert*6], vertex );
00406         VMOVE( &vert_root->the_array[vert_root->curr_vert*6+3], &vertex[3] );
00407 
00408         /* add to the tree also */
00409         new_leaf = (union vert_tree *)bu_malloc( sizeof( union vert_tree ), "new_leaf" );
00410         new_leaf->vleaf.type = VERT_LEAF;
00411         new_leaf->vleaf.index = vert_root->curr_vert++;
00412         if( !vert_root->the_tree ) {
00413                 /* first vertex, it becomes the root */
00414                 vert_root->the_tree = new_leaf;
00415         } else if( ptr && ptr->type == VERT_LEAF ) {
00416                 fastf_t max;
00417                 int i;
00418 
00419                 /* search above ended at a leaf, need to add a node above this leaf and the new leaf */
00420                 new_node = (union vert_tree *)bu_malloc( sizeof( union vert_tree ), "new_node" );
00421                 new_node->vnode.type = VERT_NODE;
00422 
00423                 /* select the cutting coord based on the biggest difference */
00424                 if( d1_sq <= local_tol_sq ) {
00425                         /* cut based on normal */
00426                         new_node->vnode.coord = 3;
00427                 } else {
00428                         new_node->vnode.coord = 0;
00429                 }
00430                 max = diff[new_node->vnode.coord];
00431                 for( i=new_node->vnode.coord+1 ; i<6 ; i++ ) {
00432                         if( diff[i] > max ) {
00433                                 new_node->vnode.coord = i;
00434                                 max = diff[i];
00435                         }
00436                 }
00437 
00438                 /* set the cut value to the mid value between the two vertices or normals */
00439                 new_node->vnode.cut_val = (vertex[new_node->vnode.coord] +
00440                                            vert_root->the_array[ptr->vleaf.index * 3 + new_node->vnode.coord]) * 0.5;
00441 
00442                 /* set the node "lower" nad "higher" pointers */
00443                 if( vertex[new_node->vnode.coord] >=
00444                     vert_root->the_array[ptr->vleaf.index * 3 + new_node->vnode.coord] ) {
00445                         new_node->vnode.higher = new_leaf;
00446                         new_node->vnode.lower = ptr;
00447                 } else {
00448                         new_node->vnode.higher = ptr;
00449                         new_node->vnode.lower = new_leaf;
00450                 }
00451 
00452                 if( ptr == vert_root->the_tree ) {
00453                         /* if the above search ended at the root, redefine the root */
00454                         vert_root->the_tree =  new_node;
00455                 } else {
00456                         /* set the previous node to point to our new one */
00457                         if( prev->vnode.higher == ptr ) {
00458                                 prev->vnode.higher = new_node;
00459                         } else {
00460                                 prev->vnode.lower = new_node;
00461                         }
00462                 }
00463         } else if( ptr && ptr->type == VERT_NODE ) {
00464                 /* above search ended at a node, just add the new leaf */
00465                 prev = ptr;
00466                 if( vertex[prev->vnode.coord] >= prev->vnode.cut_val ) {
00467                         if( prev->vnode.higher ) {
00468                             bu_bomb("higher vertex node already exists in Add_vert_and_norm()?\n");
00469                         }
00470                         prev->vnode.higher = new_leaf;
00471                 } else {
00472                         if( prev->vnode.lower ) {
00473                             bu_bomb("lower vertex node already exists in Add_vert_and_norm()?\n");
00474                         }
00475                         prev->vnode.lower = new_leaf;
00476                 }
00477         } else {
00478                 fprintf( stderr, "*********ERROR********\n" );
00479         }
00480 
00481         /* return the index into the vertex array */
00482         return( new_leaf->vleaf.index );
00483 }
00484 /*@}*/
00485 /*
00486  * Local Variables:
00487  * mode: C
00488  * tab-width: 8
00489  * c-basic-offset: 4
00490  * indent-tabs-mode: t
00491  * End:
00492  * ex: shiftwidth=4 tabstop=8
00493  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6