From b5a8683301514d420dd4becde29e4bc73165bd8f Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 4 Sep 2015 20:00:26 +0000 Subject: [PATCH] dox: basic Doxygenization of btree2/kdtree docs Include text provided by mmetz in: https://lists.osgeo.org/pipermail/grass-dev/2015-January/072701.html https://lists.osgeo.org/pipermail/grass-dev/2015-January/072784.html git-svn-id: https://svn.osgeo.org/grass/grass/trunk@66100 15284696-431f-4ddb-bdfa-cd5b030d7da7 --- lib/btree2/README | 94 ------------------- lib/btree2/btree2.dox | 175 ++++++++++++++++++++++++++++++++++++ lib/btree2/kdtree.h | 203 +++++++++++++++++++++++------------------- 3 files changed, 287 insertions(+), 185 deletions(-) delete mode 100644 lib/btree2/README create mode 100644 lib/btree2/btree2.dox diff --git a/lib/btree2/README b/lib/btree2/README deleted file mode 100644 index 74bd30f32c7..00000000000 --- a/lib/btree2/README +++ /dev/null @@ -1,94 +0,0 @@ - -Red-Black tree -============== - -#include - -and link to BTREE2LIB - -to make use of the binary balanced (Red-Black) search tree - -NOTE: duplicates are not supported - -see also grass/rbtree.h for instructions on how to use it - -/* custom compare function */ -int my_compare_fn(const void *a, const void *b) -{ - if ((mydatastruct *) a < (mydatastruct *) b) - return -1; - else if ((mydatastruct *) a > (mydatastruct *) b) - return 1; - else if ((mydatastruct *) a == (mydatastruct *) b) - return 0; -} - -/* create and initialize tree: */ -struct RB_TREE *mytree = rbtree_create(my_compare_fn, item_size); - -/* insert items to tree: */ - struct mydatastruct data = ; - - if (rbtree_insert(mytree, &data) == 0) - G_warning("could not insert data"); - -/* find item in tree: */ - struct mydatastruct data = ; - - if (rbtree_find(mytree, &data) == 0) - G_message("data not found"); - -/* delete item from tree: */ - struct mydatastruct data = ; - - if (rbtree_remove(mytree, &data) == 0) - G_warning("could not find data in tree"); - -/* traverse tree (get all items in tree in ascending order): */ - struct RB_TRAV trav; - - rbtree_init_trav(&trav, tree); - while ((data = rbtree_traverse(&trav)) != NULL) { - if (my_compare_fn(data, threshold_data) == 0) break; - /* do something with data */ - } - -/* get a selection of items: all data > data1 and < data2 - * start in tree where data is last smaller or first larger compared to data1 */ - struct RB_TRAV trav; - - rbtree_init_trav(&trav, tree); - data = rbtree_traverse_start(&trav, &data1); - /* do something with data */ - while ((data = rbtree_traverse(&trav)) != NULL) { - if (data > data2) break; - /* do something with data */ - } - -/* destroy tree: */ - rbtree_destroy(mytree); - -/* debug the whole tree with */ - rbtree_debug(mytree, mytree->root); - - -k-d tree -======== - -#include - -and link to BTREE2LIB - -/* create a new k-d tree, here 3D */ -struct kdtree *t = kdtree_create(3, NULL); - -/* insert items */ -for (i = 0; i < npoints; i++) - kdtree_insert(t, c, i, 1); - -/* find nearest neighbor for each point */ -for (i = 0; i < npoints; i++) - int found = kdtree_knn(t, c, &uid, &dist, 1, i); - -/* destroy the tree */ - kdtree_destroy(t); diff --git a/lib/btree2/btree2.dox b/lib/btree2/btree2.dox new file mode 100644 index 00000000000..688cfef7b67 --- /dev/null +++ b/lib/btree2/btree2.dox @@ -0,0 +1,175 @@ +/*! \page btree2 btree2 library + +\tableofcontents + +Red-Black tree +============== + +Include and linking +------------------- + +To make use of the binary balanced (Red-Black) search tree include: + + #include + +and link to `BTREE2LIB` in a Makefile. + +\note + Duplicates are not supported. + +Example +------- + +Define custom compare function: + + int my_compare_fn(const void *a, const void *b) + { + if ((mydatastruct *) a < (mydatastruct *) b) + return -1; + else if ((mydatastruct *) a > (mydatastruct *) b) + return 1; + else if ((mydatastruct *) a == (mydatastruct *) b) + return 0; + } + +Create and initialize tree: + + struct RB_TREE *mytree = rbtree_create(my_compare_fn, item_size); + +Insert items to tree: + + struct mydatastruct data = ; + + if (rbtree_insert(mytree, &data) == 0) + G_warning("could not insert data"); + +Find item in tree: + + struct mydatastruct data = ; + + if (rbtree_find(mytree, &data) == 0) + G_message("data not found"); + +Delete item from tree: + + struct mydatastruct data = ; + + if (rbtree_remove(mytree, &data) == 0) + G_warning("could not find data in tree"); + +Traverse tree (get all items in tree in ascending order): + + struct RB_TRAV trav; + + rbtree_init_trav(&trav, tree); + while ((data = rbtree_traverse(&trav)) != NULL) { + if (my_compare_fn(data, threshold_data) == 0) break; + // do something with data (using C++ comments because of Doxygen) + } + +Get a selection of items: all data > data1 and < data2. +Start in tree where data is last smaller or first larger compared to data1: + + struct RB_TRAV trav; + + rbtree_init_trav(&trav, tree); + data = rbtree_traverse_start(&trav, &data1); + // do something with data + while ((data = rbtree_traverse(&trav)) != NULL) { + if (data > data2) break; + // do something with data + } + +Destroy tree: + + rbtree_destroy(mytree); + +Debug the whole tree with: + + rbtree_debug(mytree, mytree->root); + +See also \ref rbtree.h for more instructions on how to use it. + + +k-d tree +======== + +Description +----------- + +k-d tree is a multidimensional (k-dimensional) binary search tree for +nearest neighbor search. + +This k-d tree finds the exact nearest neighbor(s), not some +approximation. It supports up to 255 dimensions. It is dynamic, i.e. +points can be inserted and removed at any time. It is balanced to +improve search performance. It provides k nearest neighbor search +(find k neighbors to a given coordinate) as well as radius or distance +search (find all neighbors within radius, i.e. not farther away than +radius to a given coordinate). + + +Include and linking +------------------- + +Include: + + #include + +and link to `BTREE2LIB` in a Makefile. + + +Example +------- + +Create a new k-d tree (here 3D): + + struct kdtree *t = kdtree_create(3, NULL); + +Insert items: + + for (i = 0; i < npoints; i++) + kdtree_insert(t, c, i, 1); + +Find nearest neighbor for each point: + + for (i = 0; i < npoints; i++) + int found = kdtree_knn(t, c, &uid, &dist, 1, i); + +Destroy the tree: + + kdtree_destroy(t); + + +Example usages +-------------- + +- Nearest neighbor statistics: test if points are randomly + distributed. For example, an older version of GRASS addon `v.nnstat` + used an external k-d tree from PCL (which in turn uses flann) + which finds the approximate, not the exact nearest neighbor. + The GRASS-native k-d tree always finds the real nearest neighbor. + +- Spatial cluster analysis: a point cloud can be partitioned into + separate clusters where points within each cluster are closer to each + other than to points of another cluster. For example, as used in + \gmod{v.cluster}. + +- %Point cloud thinning: a sample can be generated from a large point + cloud by specifying a minimum distance between sample points. + +- This k-d tree is used by \gmod{v.clean} `tool=snap` (Vect_snap_lines()), + reducing both memory consumption and processing time. + + +See also +======== + +- \ref rbtree.h +- \ref kdtree.h +- \ref rtree.h +- \ref btree.h +- [Wikipedia article on Red-black_tree](https://en.wikipedia.org/wiki/Red-black_tree) +- [Wikipedia article on k-d tree](https://en.wikipedia.org/wiki/K-d_tree) + +*/ diff --git a/lib/btree2/kdtree.h b/lib/btree2/kdtree.h index bef6fca7052..df7ff11b7d8 100644 --- a/lib/btree2/kdtree.h +++ b/lib/btree2/kdtree.h @@ -1,9 +1,12 @@ /*! - * \file kdtree.c + * \file kdtree.h * - * \brief binary search tree + * \brief Dynamic balanced k-d tree implementation * - * Dynamic balanced k-d tree implementation + * k-d tree is a multidimensional (k-dimensional) binary search tree for + * nearest neighbor search and is part of \ref btree2. + * + * Copyright and license: * * (C) 2014 by the GRASS Development Team * @@ -11,142 +14,160 @@ * (>=v2). Read the file COPYING that comes with GRASS for details. * * \author Markus Metz - */ - -/*********************************************************************** - * k-d tree: - * multidimensional binary search tree for nearest neighbor search - * + * + * \par References * Bentley, J. L. (1975). "Multidimensional binary search trees used for * associative searching". Communications of the ACM 18 (9): 509. * doi:10.1145/361002.361007 + * + * \par Features + * - This k-d tree is a dynamic tree: + * elements can be inserted and removed any time. + * - This k-d tree is balanced: + * subtrees have a similar depth (the difference in subtrees' depths is + * not allowed to be larger than the balancing tolerance). + * + * Here is a structure of basic usage: + * + * Create a new k-d tree: + * + * kdtree_create(...); + * + * Insert points into the tree: + * + * kdtree_insert(...); + * + * Optionally optimize the tree: * - * This k-d tree is a dynamic tree: - * elements can be inserted and removed any time - * - * this k-d tree is balanced: - * subtrees have a similar depth (the difference in subtrees' depths is - * not allowed to be larger than the balancing tolerance) - * - * USAGE: - * create a new k-d tree - * kdtree_create(); - * - * insert points into the tree - * kdtree_insert(); - * - * optionally optimize the tree: - * kdtre_optimize - * - * search k nearest neighbours - * kdtree_knn(); - * - * search all neighbors in radius - * kdtree_dnn(); - * - * destroy the tree: - * kdtree_destroy(); - * - ***********************************************************************/ + * kdtree_optimize(...); + * + * Search k nearest neighbors: + * + * kdtree_knn(...); + * + * Search all neighbors in radius: + * + * kdtree_dnn(...); + * + * Destroy the tree: + * + * kdtree_destroy(...); + * + * \todo + * Doxygen ignores comment for last parameter after `);`. + * The parameter description now goes to the end of function description. + * + * \todo + * Include formatting to function descriptions. + */ +/*! + * \brief Node for k-d tree + */ struct kdnode { - unsigned char dim; /* split dimension of this node */ - unsigned char depth; /* depth at this node */ - double *c; /* coordinates */ - int uid; /* unique id of this node */ - struct kdnode *child[2]; /* link to children: link[0] for smaller, link[1] for larger */ + unsigned char dim; /*!< split dimension of this node */ + unsigned char depth; /*!< depth at this node */ + double *c; /*!< coordinates */ + int uid; /*!< unique id of this node */ + struct kdnode *child[2]; /*!< link to children: `[0]` for smaller, `[1]` for larger */ }; +/*! + * \brief k-d tree + */ struct kdtree { - unsigned char ndims; /* number of dimensions */ - unsigned char *nextdim; /* split dimension of child nodes */ - int csize; /* size of coordinates in bytes */ - int btol; /* balancing tolerance */ - size_t count; /* number of items in the tree */ - struct kdnode *root; /* tree root */ + unsigned char ndims; /*!< number of dimensions */ + unsigned char *nextdim; /*!< split dimension of child nodes */ + int csize; /*!< size of coordinates in bytes */ + int btol; /*!< balancing tolerance */ + size_t count; /*!< number of items in the tree */ + struct kdnode *root; /*!< tree root */ }; +/*! + * \brief k-d tree traversal + */ struct kdtrav { - struct kdtree *tree; /* tree being traversed */ - struct kdnode *curr_node; /* current node */ - struct kdnode *up[256]; /* stack of parent nodes */ - int top; /* index for stack */ - int first; /* little helper flag */ + struct kdtree *tree; /*!< tree being traversed */ + struct kdnode *curr_node; /*!< current node */ + struct kdnode *up[256]; /*!< stack of parent nodes */ + int top; /*!< index for stack */ + int first; /*!< little helper flag */ }; -/* creae a new k-d tree */ -struct kdtree *kdtree_create(char ndims, /* number of dimensions */ - int *btol); /* optional balancing tolerance */ +/*! creae a new k-d tree */ +struct kdtree *kdtree_create(char ndims, /*!< number of dimensions */ + int *btol); /*!< optional balancing tolerance */ -/* destroy a tree */ +/*! destroy a tree */ void kdtree_destroy(struct kdtree *t); -/* clear a tree, removing all entries */ +/*! clear a tree, removing all entries */ void kdtree_clear(struct kdtree *t); -/* insert an item (coordinates c and uid) into the k-d tree */ -int kdtree_insert(struct kdtree *t, /* k-d tree */ - double *c, /* coordinates */ - int uid, /* the point's unique id */ - int dc); /* allow duplicate coordinates */ +/*! insert an item (coordinates c and uid) into the k-d tree */ +int kdtree_insert(struct kdtree *t, /*!< k-d tree */ + double *c, /*!< coordinates */ + int uid, /*!< the point's unique id */ + int dc); /*!< allow duplicate coordinates */ -/* remove an item from the k-d tree +/*! remove an item from the k-d tree * coordinates c and uid must match */ -int kdtree_remove(struct kdtree *t, /* k-d tree */ - double *c, /* coordinates */ - int uid); /* the point's unique id */ +int kdtree_remove(struct kdtree *t, /*!< k-d tree */ + double *c, /*!< coordinates */ + int uid); /*!< the point's unique id */ -/* find k nearest neighbors +/*! find k nearest neighbors * results are stored in uid (uids) and d (squared distances) * optionally an uid to be skipped can be given * useful when searching for the nearest neighbors of an item * that is also in the tree */ -int kdtree_knn(struct kdtree *t, /* k-d tree */ - double *c, /* coordinates */ - int *uid, /* unique ids of the neighbors */ - double *d, /* squared distances to the neighbors */ - int k, /* number of neighbors to find */ - int *skip); /* unique id to skip */ +int kdtree_knn(struct kdtree *t, /*!< k-d tree */ + double *c, /*!< coordinates */ + int *uid, /*!< unique ids of the neighbors */ + double *d, /*!< squared distances to the neighbors */ + int k, /*!< number of neighbors to find */ + int *skip); /*!< unique id to skip */ -/* find all nearest neighbors within distance aka radius search +/*! find all nearest neighbors within distance aka radius search * results are stored in puid (uids) and pd (squared distances) * memory is allocated as needed, the calling fn must free the memory * optionally an uid to be skipped can be given */ -int kdtree_dnn(struct kdtree *t, /* k-d tree */ - double *c, /* coordinates */ - int **puid, /* unique ids of the neighbors */ - double **pd, /* squared distances to the neighbors */ - double maxdist, /* radius to search around the given coordinates */ - int *skip); /* unique id to skip */ - -/* find all nearest neighbors within range aka box search +int kdtree_dnn(struct kdtree *t, /*!< k-d tree */ + double *c, /*!< coordinates */ + int **puid, /*!< unique ids of the neighbors */ + double **pd, /*!< squared distances to the neighbors */ + double maxdist, /*!< radius to search around the given coordinates */ + int *skip); /*!< unique id to skip */ + +/*! find all nearest neighbors within range aka box search * the range is specified with min and max for each dimension as * (min1, min2, ..., minn, max1, max2, ..., maxn) * results are stored in puid (uids) and pd (squared distances) * memory is allocated as needed, the calling fn must free the memory * optionally an uid to be skipped can be given */ -int kdtree_rnn(struct kdtree *t, /* k-d tree */ - double *c, /* coordinates for range */ - int **puid, /* unique ids of the neighbors */ - int *skip); /* unique id to skip */ +int kdtree_rnn(struct kdtree *t, /*!< k-d tree */ + double *c, /*!< coordinates for range */ + int **puid, /*!< unique ids of the neighbors */ + int *skip); /*!< unique id to skip */ -/* k-d tree optimization, only useful if the tree will be heavily used +/*! k-d tree optimization, only useful if the tree will be heavily used * (more searches than items in the tree) * level 0 = a bit, 1 = more, 2 = a lot */ -void kdtree_optimize(struct kdtree *t, /* k-d tree */ - int level); /* optimization level */ +void kdtree_optimize(struct kdtree *t, /*!< k-d tree */ + int level); /*!< optimization level */ -/* initialize tree traversal +/*! initialize tree traversal * (re-)sets trav structure * returns 0 */ int kdtree_init_trav(struct kdtrav *trav, struct kdtree *tree); -/* traverse the tree +/*! traverse the tree * useful to get all items in the tree non-recursively * struct kdtrav *trav needs to be initialized first * returns 1, 0 when finished