kd_dump.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------
00002 // File:                        kd_dump.cc
00003 // Programmer:          David Mount
00004 // Description:         Dump and Load for kd- and bd-trees
00005 // Last modified:       01/04/05 (Version 1.0)
00006 //----------------------------------------------------------------------
00007 // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
00008 // David Mount.  All Rights Reserved.
00009 // 
00010 // This software and related documentation is part of the Approximate
00011 // Nearest Neighbor Library (ANN).  This software is provided under
00012 // the provisions of the Lesser GNU Public License (LGPL).  See the
00013 // file ../ReadMe.txt for further information.
00014 // 
00015 // The University of Maryland (U.M.) and the authors make no
00016 // representations about the suitability or fitness of this software for
00017 // any purpose.  It is provided "as is" without express or implied
00018 // warranty.
00019 //----------------------------------------------------------------------
00020 // History:
00021 //      Revision 0.1  03/04/98
00022 //              Initial release
00023 //      Revision 1.0  04/01/05
00024 //              Moved dump out of kd_tree.cc into this file.
00025 //              Added kd-tree load constructor.
00026 //----------------------------------------------------------------------
00027 // This file contains routines for dumping kd-trees and bd-trees and
00028 // reloading them. (It is an abuse of policy to include both kd- and
00029 // bd-tree routines in the same file, sorry.  There should be no problem
00030 // in deleting the bd- versions of the routines if they are not
00031 // desired.)
00032 //----------------------------------------------------------------------
00033 
00034 #include "kd_tree.h"                                    // kd-tree declarations
00035 #include "bd_tree.h"                                    // bd-tree declarations
00036 #include <cstring>
00037 #include <cstdlib>
00038 
00039 using namespace std;                                    // make std:: available
00040 
00041 //----------------------------------------------------------------------
00042 //              Constants
00043 //----------------------------------------------------------------------
00044 
00045 const int               STRING_LEN              = 500;  // maximum string length
00046 const double    EPSILON                 = 1E-5; // small number for float comparison
00047 
00048 enum ANNtreeType {KD_TREE, BD_TREE};    // tree types (used in loading)
00049 
00050 //----------------------------------------------------------------------
00051 //              Procedure declarations
00052 //----------------------------------------------------------------------
00053 
00054 static ANNkd_ptr annReadDump(                   // read dump file
00055         istream                         &in,                                    // input stream
00056         ANNtreeType                     tree_type,                              // type of tree expected
00057         ANNpointArray           &the_pts,                               // new points (if applic)
00058         ANNidxArray                     &the_pidx,                              // point indices (returned)
00059         int                                     &the_dim,                               // dimension (returned)
00060         int                                     &the_n_pts,                             // number of points (returned)
00061         int                                     &the_bkt_size,                  // bucket size (returned)
00062         ANNpoint                        &the_bnd_box_lo,                // low bounding point
00063         ANNpoint                        &the_bnd_box_hi);               // high bounding point
00064 
00065 static ANNkd_ptr annReadTree(                   // read tree-part of dump file
00066         istream                         &in,                                    // input stream
00067         ANNtreeType                     tree_type,                              // type of tree expected
00068         ANNidxArray                     the_pidx,                               // point indices (modified)
00069         int                                     &next_idx);                             // next index (modified)
00070 
00071 //----------------------------------------------------------------------
00072 //      ANN kd- and bd-tree Dump Format
00073 //              The dump file begins with a header containing the version of
00074 //              ANN, an optional section containing the points, followed by
00075 //              a description of the tree.      The tree is printed in preorder.
00076 //
00077 //              Format:
00078 //              #ANN <version number> <comments> [END_OF_LINE]
00079 //              points <dim> <n_pts>                    (point coordinates: this is optional)
00080 //              0 <xxx> <xxx> ... <xxx>                 (point indices and coordinates)
00081 //              1 <xxx> <xxx> ... <xxx>
00082 //                ...
00083 //              tree <dim> <n_pts> <bkt_size>
00084 //              <xxx> <xxx> ... <xxx>                   (lower end of bounding box)
00085 //              <xxx> <xxx> ... <xxx>                   (upper end of bounding box)
00086 //                              If the tree is null, then a single line "null" is
00087 //                              output.  Otherwise the nodes of the tree are printed
00088 //                              one per line in preorder.  Leaves and splitting nodes 
00089 //                              have the following formats:
00090 //              Leaf node:
00091 //                              leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
00092 //              Splitting nodes:
00093 //                              split <cut_dim> <cut_val> <lo_bound> <hi_bound>
00094 //
00095 //              For bd-trees:
00096 //
00097 //              Shrinking nodes:
00098 //                              shrink <n_bnds>
00099 //                                              <cut_dim> <cut_val> <side>
00100 //                                              <cut_dim> <cut_val> <side>
00101 //                                              ... (repeated n_bnds times)
00102 //----------------------------------------------------------------------
00103 
00104 void ANNkd_tree::Dump(                                  // dump entire tree
00105                 ANNbool with_pts,                               // print points as well?
00106                 ostream &out)                                   // output stream
00107 {
00108         out << "#ANN " << ANNversion << "\n";
00109         out.precision(ANNcoordPrec);            // use full precision in dumping
00110         if (with_pts) {                                         // print point coordinates
00111                 out << "points " << dim << " " << n_pts << "\n";
00112                 for (int i = 0; i < n_pts; i++) {
00113                         out << i << " ";
00114                         annPrintPt(pts[i], dim, out);
00115                         out << "\n";
00116                 }
00117         }
00118         out << "tree "                                          // print tree elements
00119                 << dim << " "
00120                 << n_pts << " "
00121                 << bkt_size << "\n";
00122 
00123         annPrintPt(bnd_box_lo, dim, out);       // print lower bound
00124         out << "\n";
00125         annPrintPt(bnd_box_hi, dim, out);       // print upper bound
00126         out << "\n";
00127 
00128         if (root == NULL)                                       // empty tree?
00129                 out << "null\n";
00130         else {
00131                 root->dump(out);                                // invoke printing at root
00132         }
00133         out.precision(0);                                       // restore default precision
00134 }
00135 
00136 void ANNkd_split::dump(                                 // dump a splitting node
00137                 ostream &out)                                   // output stream
00138 {
00139         out << "split " << cut_dim << " " << cut_val << " ";
00140         out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n";
00141 
00142         child[ANN_LO]->dump(out);                       // print low child
00143         child[ANN_HI]->dump(out);                       // print high child
00144 }
00145 
00146 void ANNkd_leaf::dump(                                  // dump a leaf node
00147                 ostream &out)                                   // output stream
00148 {
00149         if (this == KD_TRIVIAL) {                       // canonical trivial leaf node
00150                 out << "leaf 0\n";                              // leaf no points
00151         }
00152         else{
00153                 out << "leaf " << n_pts;
00154                 for (int j = 0; j < n_pts; j++) {
00155                         out << " " << bkt[j];
00156                 }
00157                 out << "\n";
00158         }
00159 }
00160 
00161 void ANNbd_shrink::dump(                                // dump a shrinking node
00162                 ostream &out)                                   // output stream
00163 {
00164         out << "shrink " << n_bnds << "\n";
00165         for (int j = 0; j < n_bnds; j++) {
00166                 out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n";
00167         }
00168         child[ANN_IN]->dump(out);                       // print in-child
00169         child[ANN_OUT]->dump(out);                      // print out-child
00170 }
00171 
00172 //----------------------------------------------------------------------
00173 // Load kd-tree from dump file
00174 //              This rebuilds a kd-tree which was dumped to a file.      The dump
00175 //              file contains all the basic tree information according to a
00176 //              preorder traversal.      We assume that the dump file also contains
00177 //              point data.      (This is to guarantee the consistency of the tree.)
00178 //              If not, then an error is generated.
00179 //
00180 //              Indirectly, this procedure allocates space for points, point
00181 //              indices, all nodes in the tree, and the bounding box for the
00182 //              tree.  When the tree is destroyed, all but the points are
00183 //              deallocated.
00184 //
00185 //              This routine calls annReadDump to do all the work.
00186 //----------------------------------------------------------------------
00187 
00188 ANNkd_tree::ANNkd_tree(                                 // build from dump file
00189         istream                         &in)                                    // input stream for dump file
00190 {
00191         int the_dim;                                                            // local dimension
00192         int the_n_pts;                                                          // local number of points
00193         int the_bkt_size;                                                       // local number of points
00194         ANNpoint the_bnd_box_lo;                                        // low bounding point
00195         ANNpoint the_bnd_box_hi;                                        // high bounding point
00196         ANNpointArray the_pts;                                          // point storage
00197         ANNidxArray the_pidx;                                           // point index storage
00198         ANNkd_ptr the_root;                                                     // root of the tree
00199 
00200         the_root = annReadDump(                                         // read the dump file
00201                 in,                                                                             // input stream
00202                 KD_TREE,                                                                // expecting a kd-tree
00203                 the_pts,                                                                // point array (returned)
00204                 the_pidx,                                                               // point indices (returned)
00205                 the_dim, the_n_pts, the_bkt_size,               // basic tree info (returned)
00206                 the_bnd_box_lo, the_bnd_box_hi);                // bounding box info (returned)
00207 
00208                                                                                                 // create a skeletal tree
00209         SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
00210 
00211         bnd_box_lo = the_bnd_box_lo;
00212         bnd_box_hi = the_bnd_box_hi;
00213 
00214         root = the_root;                                                        // set the root
00215 }
00216 
00217 ANNbd_tree::ANNbd_tree(                                 // build bd-tree from dump file
00218         istream                         &in) : ANNkd_tree()             // input stream for dump file
00219 {
00220         int the_dim;                                                            // local dimension
00221         int the_n_pts;                                                          // local number of points
00222         int the_bkt_size;                                                       // local number of points
00223         ANNpoint the_bnd_box_lo;                                        // low bounding point
00224         ANNpoint the_bnd_box_hi;                                        // high bounding point
00225         ANNpointArray the_pts;                                          // point storage
00226         ANNidxArray the_pidx;                                           // point index storage
00227         ANNkd_ptr the_root;                                                     // root of the tree
00228 
00229         the_root = annReadDump(                                         // read the dump file
00230                 in,                                                                             // input stream
00231                 BD_TREE,                                                                // expecting a bd-tree
00232                 the_pts,                                                                // point array (returned)
00233                 the_pidx,                                                               // point indices (returned)
00234                 the_dim, the_n_pts, the_bkt_size,               // basic tree info (returned)
00235                 the_bnd_box_lo, the_bnd_box_hi);                // bounding box info (returned)
00236 
00237                                                                                                 // create a skeletal tree
00238         SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
00239         bnd_box_lo = the_bnd_box_lo;
00240         bnd_box_hi = the_bnd_box_hi;
00241 
00242         root = the_root;                                                        // set the root
00243 }
00244 
00245 //----------------------------------------------------------------------
00246 //      annReadDump - read a dump file
00247 //
00248 //              This procedure reads a dump file, constructs a kd-tree
00249 //              and returns all the essential information needed to actually
00250 //              construct the tree.      Because this procedure is used for
00251 //              constructing both kd-trees and bd-trees, the second argument
00252 //              is used to indicate which type of tree we are expecting.
00253 //----------------------------------------------------------------------
00254 
00255 static ANNkd_ptr annReadDump(
00256         istream                         &in,                                    // input stream
00257         ANNtreeType                     tree_type,                              // type of tree expected
00258         ANNpointArray           &the_pts,                               // new points (returned)
00259         ANNidxArray                     &the_pidx,                              // point indices (returned)
00260         int                                     &the_dim,                               // dimension (returned)
00261         int                                     &the_n_pts,                             // number of points (returned)
00262         int                                     &the_bkt_size,                  // bucket size (returned)
00263         ANNpoint                        &the_bnd_box_lo,                // low bounding point (ret'd)
00264         ANNpoint                        &the_bnd_box_hi)                // high bounding point (ret'd)
00265 {
00266         int j;
00267         char str[STRING_LEN];                                           // storage for string
00268         char version[STRING_LEN];                                       // ANN version number
00269         ANNkd_ptr the_root = NULL;
00270 
00271         //------------------------------------------------------------------
00272         //      Input file header
00273         //------------------------------------------------------------------
00274         in >> str;                                                                      // input header
00275         if (strcmp(str, "#ANN") != 0) {                         // incorrect header
00276                 annError("Incorrect header for dump file", ANNabort);
00277         }
00278         in.getline(version, STRING_LEN);                        // get version (ignore)
00279 
00280         //------------------------------------------------------------------
00281         //      Input the points
00282         //                      An array the_pts is allocated and points are read from
00283         //                      the dump file.
00284         //------------------------------------------------------------------
00285         in >> str;                                                                      // get major heading
00286         if (strcmp(str, "points") == 0) {                       // points section
00287                 in >> the_dim;                                                  // input dimension
00288                 in >> the_n_pts;                                                // number of points
00289                                                                                                 // allocate point storage
00290                 the_pts = annAllocPts(the_n_pts, the_dim);
00291                 for (int i = 0; i < the_n_pts; i++) {   // input point coordinates
00292                         ANNidx idx;                                                     // point index
00293                         in >> idx;                                                      // input point index
00294                         if (idx < 0 || idx >= the_n_pts) {
00295                                 annError("Point index is out of range", ANNabort);
00296                         }
00297                         for (j = 0; j < the_dim; j++) {
00298                                 in >> the_pts[idx][j];                  // read point coordinates
00299                         }
00300                 }
00301                 in >> str;                                                              // get next major heading
00302         }
00303         else {                                                                          // no points were input
00304                 annError("Points must be supplied in the dump file", ANNabort);
00305         }
00306 
00307         //------------------------------------------------------------------
00308         //      Input the tree
00309         //                      After the basic header information, we invoke annReadTree
00310         //                      to do all the heavy work.  We create our own array of
00311         //                      point indices (so we can pass them to annReadTree())
00312         //                      but we do not deallocate them.  They will be deallocated
00313         //                      when the tree is destroyed.
00314         //------------------------------------------------------------------
00315         if (strcmp(str, "tree") == 0) {                         // tree section
00316                 in >> the_dim;                                                  // read dimension
00317                 in >> the_n_pts;                                                // number of points
00318                 in >> the_bkt_size;                                             // bucket size
00319                 the_bnd_box_lo = annAllocPt(the_dim);   // allocate bounding box pts
00320                 the_bnd_box_hi = annAllocPt(the_dim);
00321 
00322                 for (j = 0; j < the_dim; j++) {                 // read bounding box low
00323                         in >> the_bnd_box_lo[j];
00324                 }
00325                 for (j = 0; j < the_dim; j++) {                 // read bounding box low
00326                         in >> the_bnd_box_hi[j];
00327                 }
00328                 the_pidx = new ANNidx[the_n_pts];               // allocate point index array
00329                 int next_idx = 0;                                               // number of indices filled
00330                                                                                                 // read the tree and indices
00331                 the_root = annReadTree(in, tree_type, the_pidx, next_idx);
00332                 if (next_idx != the_n_pts) {                    // didn't see all the points?
00333                         annError("Didn't see as many points as expected", ANNwarn);
00334                 }
00335         }
00336         else {
00337                 annError("Illegal dump format.  Expecting section heading", ANNabort);
00338         }
00339         return the_root;
00340 }
00341 
00342 //----------------------------------------------------------------------
00343 // annReadTree - input tree and return pointer
00344 //
00345 //              annReadTree reads in a node of the tree, makes any recursive
00346 //              calls as needed to input the children of this node (if internal).
00347 //              It returns a pointer to the node that was created.      An array
00348 //              of point indices is given along with a pointer to the next
00349 //              available location in the array.  As leaves are read, their
00350 //              point indices are stored here, and the point buckets point
00351 //              to the first entry in the array.
00352 //
00353 //              Recall that these are the formats.      The tree is given in
00354 //              preorder.
00355 //
00356 //              Leaf node:
00357 //                              leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
00358 //              Splitting nodes:
00359 //                              split <cut_dim> <cut_val> <lo_bound> <hi_bound>
00360 //
00361 //              For bd-trees:
00362 //
00363 //              Shrinking nodes:
00364 //                              shrink <n_bnds>
00365 //                                              <cut_dim> <cut_val> <side>
00366 //                                              <cut_dim> <cut_val> <side>
00367 //                                              ... (repeated n_bnds times)
00368 //----------------------------------------------------------------------
00369 
00370 static ANNkd_ptr annReadTree(
00371         istream                         &in,                                    // input stream
00372         ANNtreeType                     tree_type,                              // type of tree expected
00373         ANNidxArray                     the_pidx,                               // point indices (modified)
00374         int                                     &next_idx)                              // next index (modified)
00375 {
00376         char tag[STRING_LEN];                                           // tag (leaf, split, shrink)
00377         int n_pts;                                                                      // number of points in leaf
00378         int cd;                                                                         // cut dimension
00379         ANNcoord cv;                                                            // cut value
00380         ANNcoord lb;                                                            // low bound
00381         ANNcoord hb;                                                            // high bound
00382         int n_bnds;                                                                     // number of bounding sides
00383         int sd;                                                                         // which side
00384 
00385         in >> tag;                                                                      // input node tag
00386 
00387         if (strcmp(tag, "null") == 0) {                         // null tree
00388                 return NULL;
00389         }
00390         //------------------------------------------------------------------
00391         //      Read a leaf
00392         //------------------------------------------------------------------
00393         if (strcmp(tag, "leaf") == 0) {                         // leaf node
00394 
00395                 in >> n_pts;                                                    // input number of points
00396                 int old_idx = next_idx;                                 // save next_idx
00397                 if (n_pts == 0) {                                               // trivial leaf
00398                         return KD_TRIVIAL;
00399                 }
00400                 else {
00401                         for (int i = 0; i < n_pts; i++) {       // input point indices
00402                                 in >> the_pidx[next_idx++];             // store in array of indices
00403                         }
00404                 }
00405                 return new ANNkd_leaf(n_pts, &the_pidx[old_idx]);
00406         }
00407         //------------------------------------------------------------------
00408         //      Read a splitting node
00409         //------------------------------------------------------------------
00410         else if (strcmp(tag, "split") == 0) {           // splitting node
00411 
00412                 in >> cd >> cv >> lb >> hb;
00413 
00414                                                                                                 // read low and high subtrees
00415                 ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx);
00416                 ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx);
00417                                                                                                 // create new node and return
00418                 return new ANNkd_split(cd, cv, lb, hb, lc, hc);
00419         }
00420         //------------------------------------------------------------------
00421         //      Read a shrinking node (bd-tree only)
00422         //------------------------------------------------------------------
00423         else if (strcmp(tag, "shrink") == 0) {          // shrinking node
00424                 if (tree_type != BD_TREE) {
00425                         annError("Shrinking node not allowed in kd-tree", ANNabort);
00426                 }
00427 
00428                 in >> n_bnds;                                                   // number of bounding sides
00429                                                                                                 // allocate bounds array
00430                 ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds];
00431                 for (int i = 0; i < n_bnds; i++) {
00432                         in >> cd >> cv >> sd;                           // input bounding halfspace
00433                                                                                                 // copy to array
00434                         bds[i] = ANNorthHalfSpace(cd, cv, sd);
00435                 }
00436                                                                                                 // read inner and outer subtrees
00437                 ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx);
00438                 ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx);
00439                                                                                                 // create new node and return
00440                 return new ANNbd_shrink(n_bnds, bds, ic, oc);
00441         }
00442         else {
00443                 annError("Illegal node type in dump file", ANNabort);
00444                 exit(0);                                                                // to keep the compiler happy
00445         }
00446 }

Generated on Wed Nov 23 19:00:20 2011 for FreeCAD by  doxygen 1.6.1