{"id":17789533,"url":"https://github.com/ehwan/r-star-tree","last_synced_at":"2025-10-09T12:09:36.321Z","repository":{"id":217312026,"uuid":"743043756","full_name":"ehwan/R-Star-Tree","owner":"ehwan","description":"HeaderOnly STL-like template N-dimensional R*Tree implementation on C++14","archived":false,"fork":false,"pushed_at":"2025-01-01T04:35:05.000Z","size":1153,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-07T13:54:31.114Z","etag":null,"topics":["algorithm","cplusplus-14","cuda","eigen3","geometric-algorithms","gpgpu","header-only","linear-algebra","modern-cpp","opencl","rtree","spatial","spatial-index","stl-like","template","traits","tree-structure"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ehwan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-14T06:20:24.000Z","updated_at":"2025-01-01T06:47:52.000Z","dependencies_parsed_at":"2024-05-18T15:45:06.761Z","dependency_job_id":null,"html_url":"https://github.com/ehwan/R-Star-Tree","commit_stats":null,"previous_names":["ehwan/rtree","ehwan/r-star-tree"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehwan%2FR-Star-Tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehwan%2FR-Star-Tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehwan%2FR-Star-Tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehwan%2FR-Star-Tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ehwan","download_url":"https://codeload.github.com/ehwan/R-Star-Tree/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243814880,"owners_count":20352037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","cplusplus-14","cuda","eigen3","geometric-algorithms","gpgpu","header-only","linear-algebra","modern-cpp","opencl","rtree","spatial","spatial-index","stl-like","template","traits","tree-structure"],"created_at":"2024-10-27T10:34:10.140Z","updated_at":"2025-10-09T12:09:31.263Z","avatar_url":"https://github.com/ehwan.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# R-Star-Tree\nHeader-Only N-dimensional [R-Tree](https://en.wikipedia.org/wiki/R-tree), [R*-Tree](https://en.wikipedia.org/wiki/R*-tree) implementation on Modern C++\n\nAnd some features to read-only query in GPU ( CUDA, OpenCL, etc. )\n\n\n![](example/visualize_2d/images/animation.gif)\n\nThe bounding boxes on the graph indicate the coverage range of each node. Additionally, the thickness and color of these bounding boxes are about their respective levels. 'blue', 'orange', and 'black' are used to represent levels 2, 1, and 0, respectively.\n\nPurple dots represent input points (N = 1000), generated from a normal distribution with an origin of (0,0), a mean ($\\mu$) of 0, and a standard deviation ($\\sigma$) of 5.\n\nBoth the Splitting scheme and reinsertion algorithm applied.\n\n## Features\n - Header-Only\n - N-dimensional [R-Tree](https://en.wikipedia.org/wiki/R*-tree), [R*-Tree](https://en.wikipedia.org/wiki/R*-tree) implementation\n - Customizable types ( bounding box, key, data ) with `geometry_traits`\n - convert to contiguous memory layout Read-only query in GPU ( CUDA, OpenCL, etc. )\n - Quadratic Split, [R*-Tree Axis Split](https://en.wikipedia.org/wiki/R*-tree) (default)\n - Reinsert scheme\n\n## References\n Guttman, A. (1984). \"R-Trees: A Dynamic Index Structure for Spatial Searching\". Proceedings of the 1984 ACM SIGMOD international conference on Management of data – SIGMOD '84. p. 47.\n\n Norbert Beckmann, Hans-Peter begel, Ralf Schneider, Bernhard Seeger (1990). \"The R*-tree: An Efficient and Robust Access Method for Points and Rectangles\". Proceedings of the 1990 ACM SIGMOD international conference on Management of data - SIGMOD '90. p. 322-331.\n\n## Dependencies\n **No dependencies required** for core library.\n\n Unit Tests are using [Google Test](https://github.com/google/googletest), examples are using [Eigen](https://eigen.tuxfamily.org/).\n\n## Sample Codes\n```cpp\nint main()\n{\n  // ***************************\n  // one-dimension RTree example\n  // ***************************\n\n  rtree_type rtree;\n\n  // insert 50 arithmetic sequence of points\n  for (int i = 0; i \u003c 50; ++i)\n  {\n    double point = i;\n    int value = i;\n    rtree.insert(value_type(point, value));\n  }\n\n  // rtree.begin(), rtree.end()\n  // iterates over all values in the tree\n  for (value_type value : rtree)\n  {\n    std::cout \u003c\u003c \"Value Inserted: [\" \u003c\u003c value.first \u003c\u003c \", \" \u003c\u003c value.second \u003c\u003c \"]\\n\";\n  }\n\n  auto geometry_filter = [](aabb_type const\u0026 bound) -\u003e int\n  {\n    // if bound does not touch [10,20] skip\n    if (bound.min_ \u003e 20 || bound.max_ \u003c 10)\n      return 0;\n    return 1;\n  };\n  auto data_functor = [](std::pair\u003cdouble, int\u003e value) -\u003e bool\n  {\n    std::cout \u003c\u003c \"Value Found: [\" \u003c\u003c value.first \u003c\u003c \", \" \u003c\u003c value.second\n              \u003c\u003c \"]\\n\";\n    return false;\n  };\n\n  rtree.search(geometry_filter, data_functor);\n}\n```\n\n## Step-by-Step Guide\n### Installation\nHeader-Only library, just include `RTree.hpp` in your project.\n\n### Namespace\nEvery class and functions are under `eh::rtree` namespace.\n```cpp\nnamespace eh { namespace rtree {\n  ...\n}}\n```\n\n\n### `RTree` class\n```cpp\ntemplate \u003ctypename GeometryType,\n          typename KeyType,\n          typename MappedType,\n          typename Config = DefaultConfig,\n          template \u003ctypename _T\u003e class Allocator = std::allocator // allocator\n          \u003e\nclass RTree\n```\n\n - `GeometryType`: Type representing the Axis-Aligned Bounding Box (AABB) in N-dimensional space. Must implement [`geometry_traits`](#geometry_traits-class) for the type.\n - `KeyType`: Type of the key used to `(key, value)` pair of user inserted data. Must implement [`geometry_traits`](#geometry_traits-class) for the type.\n - `MappedType`: Type of the value used to `(key, value)` pair of user inserted data.\n - `Config`: [Configuration class](#config-class) for R-Tree. Default is `DefaultConfig`.\n - `Allocator`: Allocator for internal data structure. Default is `std::allocator`.\n\n #### Type aliases\n | Type | Description |\n | --- | --- |\n  | `value_type` | `std::pair\u003cKeyType, MappedType\u003e` |\n  | `node_type` | Internal non-leaf node type |\n  | `leaf_type` | Internal leaf node type |\n  | `iterator` | Bidirectional iterator |\n  | `const_iterator` | Const bidirectional iterator |\n\n #### Member functions\n  | Function | Description |\n  | --- | --- |\n  | `insert(value_type value)`, `emplace( ... )` | Insert a value into the R-Tree |\n  | `clear()` | Clear the R-Tree |\n  | [`begin()`, `end()`](#with-rtreeiterator) | Iterator to the beginning and end of the R-Tree |\n  | [`node_begin(lv)`, `node_end(lv)`, `leaf_begin()`, `leaf_end()`](#with-rtreeiterator) | Iterator to the every nodes on specific level |\n  | [`root()`](#directly-accessing-node-pointer) | Get the root node of the R-Tree |\n  | [`leaf_level()`](#directly-accessing-node-pointer) | Get the level of the leaf nodes in the R-Tree |\n  | [`flatten()`, `flatten_move()`](#for-read-only-usage-in-gpu--cuda-opencl-etc-) | Convert the R-Tree structure to a dense linear 1D buffer |\n  | [`rebalance()`](#dealing-with-moving-objects) | Rebalance the bounding box distribution of the R-Tree by reinserting whole data |\n  | [`rebound( iterator )`](#dealing-with-moving-objects) | Recalculate the bounding box of given node and broadcast to its parent recursively. |\n\n#### `Config` class\n```cpp\nstruct MyConfig\n{\n  constexpr static size_type MIN_ENTRIES = 4;\n  constexpr static size_type MAX_ENTRIES = 8;\n  constexpr static size_type REINSERT_COUNT = 3;\n  using split_algorithm = RStarSplit;\n};\n```\n - `MIN_ENTRIES`: Minimum number of entries in a node. Default is 4.\n - `MAX_ENTRIES`: Maximum number of entries in a node. Default is 8.\n - `REINSERT_COUNT`: Number of entries to be reinserted when node overflow occurs. Default is 3.\n - `split_algorithm`: Splitting scheme for node overflow. Either `QuadraticSplit` or `RStarSplit`. Default is `RStarSplit`.\n\n\nLike other self-balancing trees, R-Tree balances the number of children in each node.\nThe number of children in each node is determined by `MIN_ENTRIES` and `MAX_ENTRIES`.\nWhen the number of children exceeds `MAX_ENTRIES`, there are 2 ways of handling the overflow: *Reinsertion* and *Splitting*.\n`REINSERT_COUNT` is the number of entries to be reinserted when node overflow occurs.\n`split_algorithm` is the splitting scheme for node overflow.\n\n***Note***:\n - At the memory aspect, at least `MIN_ENTRIES` data are lied sequentially on memory.\n - `MIN_ENTRIES` must be less or equal to `MAX_ENTRIES/2`.\n - `MIN_ENTRIES` \u003c= `MAX_ENTRIES` + 1 - `REINSERT_COUNT` \u003c= `MAX_ENTRIES`.\n\n### `geometry_traits` class\n```cpp\ntemplate \u003c\u003e\nstruct geometry_traits\u003c Eigen::Vector3d \u003e\n{\n  // dimension\n  constexpr static int DIM = 3;\n\n  using scalar_type = double;\n\n  static scalar_type min_point(Eigen::Vector3d const\u0026 g, int axis)\n  {\n    return g.min_bound[axis];\n  }\n  static scalar_type max_point(Eigen::Vector3d const\u0026 g, int axis)\n  {\n    return g.max_bound[axis];\n  }\n  static void set_min_point(Eigen::Vector3d\u0026 g, int axis, scalar_type value)\n  {\n    g.min_bound[axis] = value;\n  }\n  static void set_max_point(Eigen::Vector3d\u0026 g, int axis, scalar_type value)\n  {\n    g.max_bound[axis] = value;\n  }\n};\n```\n  - `DIM`: Dimension of the geometry type.\n  - `scalar_type`: Type representing the scalar value of the geometry type. ( eg. `double` for `Eigen::Vector3d`, `int` for `Eigen::Vector2i` )\n  - `min_point`: Get the scalar value of the minimum point in the given axis.\n  - `max_point`: Get the scalar value of the maximum point in the given axis.\n  - `set_min_point`: Set the scalar value of the minimum point in the given axis. ( Not required for `KeyType` )\n  - `set_max_point`: Set the scalar value of the maximum point in the given axis. ( Not required for `KeyType` )\n\nBoth `GeometryType` and `KeyType` must implement `geometry_traits` to be used in `RTree`.\nUser must specify what dimension is, and how to access the scalar data of the geometry object.\nFor type used in `KeyType`, `set_min_point` and `set_max_point` are not required.\n\n### Querying with `RTree::search()`\n```cpp\ntemplate \u003ctypename GeometryFilter, typename DataFunctor\u003e\nvoid search(GeometryFilter\u0026\u0026 geometry_filter, DataFunctor\u0026\u0026 data_functor);\n\ntemplate \u003ctypename GeometryFilter, typename ConstDataFunctor\u003e\nvoid search(GeometryFilter\u0026\u0026 geometry_filter, ConstDataFunctor\u0026\u0026 data_functor) const;\n\ntemplate \u003ctypename GeometryFilter, typename ItFunctor\u003e\nvoid search_iterator(GeometryFilter\u0026\u0026 geometry_filter, ItFunctor\u0026\u0026 it_functor);\n\ntemplate \u003ctypename GeometryFilter, typename ConstItFunctor\u003e\nvoid search_iterator(GeometryFilter\u0026\u0026 geometry_filter, ConstItFunctor\u0026\u0026 it_functor) const;\n```\n- `GeometryFilter`: A callable object that takes a `GeometryType` and returns a integer value. \n    - If the return value is `1`, search will be performed recursively on the children of the node.\n    - If the return value is `0`, every child of this node will be ignored.\n    - If the return value is `-1`, the search will immediately stop and return out of the `search` function.\n- `DataFunctor`: A callable object that takes a `value_type\u0026` (or `value_type const\u0026` ) and returns boolean value.\n  If the return value is `true`, the query will immediately stop and return out of the `search` function.\n- `ItFunctor`: A callable object that takes a `iterator` (or `const_iterator`) and returns boolean value.\n  If the return value is `true`, the query will immediately stop and return out of the `search` function.\n  This is useful when you want to modify the `key` of some data.\n\n```cpp\n// Example usage of the search function\nrtree_type rtree = /* construct and populate your RTree */;\n\nauto geometry_filter = []( my_rect const\u0026 rect ) -\u003e int\n{\n  // return 1 if the rect intersects with the query range\n  // return 0 if the rect is completely outside the query range\n  // return -1 if the search should stop\n  return rect.intersects_with_query_range() ? 1 : 0;\n};\nauto data_functor = []( std::pair\u003ckey_type, mapped_type\u003e const\u0026 value ) -\u003e bool\n{\n  // return true if the query is satisfied\n  return value.first == query_key;\n};\nrtree.search( geometry_filter, data_functor );\n```\n\n### RTree traversal\n#### With `RTree::iterator`\nUser can fetch the iterators by `RTree::begin()` and `RTree::end()`.\nrange-based for loop is also available.\n\n```cpp\nfor(RTree::value_type value : rtree)\n{\n  // value.first is key, value.second is data\n}\n```\nhere, `value_type` is `std::pair\u003cKeyType, MappedType\u003e`\n\n\n#### Directly accessing node pointer\n`RTree::root()` returns the root node pointer of the R-Tree.\n\n`RTree::leaf_level()` returns the level of the where leaf nodes are.\nUser must be aware of the level of the node, and cast it to `leaf_type` if the node you are accessing is a leaf node.\n\nFor non-leaf nodes,\nUser can iterate over the children of the node by `for (RTree::node_type::value_type child : *node) { ... }`,\nwhere `value_type` is `std::pair\u003cGeometryType, RTree::node_type*\u003e`.\n\nFor leaf nodes,\nUser can iterate over the children of the leaves by `for (RTree::leaf_type::value_type child : *leaf) { ... }`,\nwhere `value_type` is `std::pair\u003cKeyType, MappedType\u003e`.\n\n### For read-only usage in GPU ( CUDA, OpenCL, etc. )\n`RTree::flatten()` and `RTree::flatten_move()` functions are provided to convert RTree structure to linear array. From this dense array, you can easily load it to GPU memory.\n\n```cpp\n// Example usage of the flatten function\nrtree_type rtree = /* construct and populate your RTree */;\nrtree_type::flatten_result_t flatten = rtree.flatten();\n\n// Now you can load 'flatten' into GPU memory for processing\n```\n\n#### flatten_result_t structure\n\nThe return type of `RTree::flatten()` is `flatten_result_t`, which contains all the necessary information to query RTree structure.\n```cpp\nstruct flatten_result_t\n{\n  // leaf node's level\n  size_type leaf_level;\n\n  // root node index; must be 0\n  size_type root;\n\n  // node information ( include leaf nodes )\n  std::vector\u003cflatten_node_t\u003e nodes;\n\n  // global dense buffer of children_boundingbox\n  std::vector\u003cgeometry_type\u003e children_bound;\n  // global dense buffer of children index\n  std::vector\u003csize_type\u003e children;\n\n  // inserted data\n  std::vector\u003cmapped_type\u003e data;\n};\n```\n - `leaf_level`: Indicates the level of the leaf nodes in the tree.\n - `root`: The index of the root node in the nodes array. This must always be 0.\n - `nodes`: A vector containing all the nodes of the RTree, including both internal and leaf nodes.\n - `children_bound`: A global dense buffer holding the bounding boxes of all children nodes.\n - `children`: A global dense buffer holding the indices of all children nodes.\n - `data`: A vector containing the actual data stored in the leaf nodes.\n\n\n#### flatten_node_t structure\n```cpp\n// node information\nstruct flatten_node_t\n{\n  // offset in global dense buffer\n  size_type offset;\n\n  // the number of children\n  size_type size;\n\n  // Can retrieve child node's information by\n  // children_bound[ offset + i ] and children[ offset + i ]\n  // for i in range(0 ... size)\n\n  // for leaf node ( level == leaf_level ),\n  // children[ offset + i ] is the index on array 'data'\n  // which is, the real data you inserted\n\n  // for normal node ( level \u003c leaf_level ),\n  // children[ offset + i ] is the index on array 'nodes'\n\n  // nodes[0] is the root node\n\n  // parent node index\n  size_type parent;\n};\n```\n - `offset`: Indicates the starting position in the global dense buffers (children_bound and children) for the children of this node.\n - `size`: The number of children this node has.\n - `parent`: The index of the parent node in the nodes array.\n\n The children of a node can be retrieved using the offset and size values. For leaf nodes (where level == leaf_level), the children array points to indices in the data array. For non-leaf nodes (where level \u003c leaf_level), the children array points to indices in the nodes array.\n\n ### Dealing with moving objects\nIf you are dealing with moving objects,\nyou can use `RTree::rebound( iterator )` function to update the bounding box of the given node.\nThis function will recalculate the bounding box of all ancestors of the given node.\nNote that this function will not *rebalance* the R-Tree, so you may need to call `RTree::rebalance()` occasionally.\n`RTree::rebalance()` will reinsert all the data to the new R-Tree, to make the bounding box distribution more balanced.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehwan%2Fr-star-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fehwan%2Fr-star-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehwan%2Fr-star-tree/lists"}