{"id":25098168,"url":"https://github.com/habedi/spart","last_synced_at":"2025-10-23T17:57:56.080Z","repository":{"id":276264522,"uuid":"926174924","full_name":"habedi/spart","owner":"habedi","description":"A collection of space partitioning trees for Rust 🦀","archived":false,"fork":false,"pushed_at":"2025-03-15T09:05:25.000Z","size":53,"stargazers_count":12,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-15T09:29:22.565Z","etag":null,"topics":["bsp-tree","indexing","kd-tree","knn-search","octree","quadtree","range-search","rtree","rust-lang","rust-library","space-partition-tree"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/habedi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2025-02-02T18:17:52.000Z","updated_at":"2025-03-07T04:27:27.000Z","dependencies_parsed_at":"2025-03-15T18:15:14.603Z","dependency_job_id":null,"html_url":"https://github.com/habedi/spart","commit_stats":null,"previous_names":["habedi/spart"],"tags_count":4,"template":false,"template_full_name":"habedi/template-rust-project","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/habedi%2Fspart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/habedi%2Fspart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/habedi%2Fspart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/habedi%2Fspart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/habedi","download_url":"https://codeload.github.com/habedi/spart/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246752616,"owners_count":20827987,"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":["bsp-tree","indexing","kd-tree","knn-search","octree","quadtree","range-search","rtree","rust-lang","rust-library","space-partition-tree"],"created_at":"2025-02-07T18:19:56.858Z","updated_at":"2025-10-23T17:57:56.072Z","avatar_url":"https://github.com/habedi.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003cimg alt=\"Spart Logo\" src=\"logo.svg\" height=\"30%\" width=\"30%\"\u003e\n  \u003c/picture\u003e\n\u003cbr\u003e\n\n\u003ch2\u003eSpart\u003c/h2\u003e\n\n[![Tests](https://img.shields.io/github/actions/workflow/status/habedi/spart/tests.yml?label=tests\u0026style=flat\u0026labelColor=282c34\u0026logo=github)](https://github.com/habedi/spart/actions/workflows/tests.yml)\n[![Code Coverage](https://img.shields.io/codecov/c/github/habedi/spart?label=coverage\u0026style=flat\u0026labelColor=282c34\u0026logo=codecov)](https://codecov.io/gh/habedi/spart)\n[![Code Quality](https://img.shields.io/codefactor/grade/github/habedi/spart?label=quality\u0026style=flat\u0026labelColor=282c34\u0026logo=codefactor)](https://www.codefactor.io/repository/github/habedi/spart)\n[![Crates.io](https://img.shields.io/crates/v/spart.svg?label=crates.io\u0026style=flat\u0026labelColor=282c34\u0026color=fc8d62\u0026logo=rust)](https://crates.io/crates/spart)\n[![Docs.rs](https://img.shields.io/badge/docs-spart-66c2a5?style=flat\u0026labelColor=282c34\u0026logo=docs.rs)](https://docs.rs/spart)\n[![MSRV](https://img.shields.io/badge/msrv-1.83.0-informational?style=flat\u0026labelColor=282c34\u0026logo=rust)](https://www.rust-lang.org)\n[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-007ec6?style=flat\u0026labelColor=282c34\u0026logo=open-source-initiative)](https://github.com/habedi/spart)\n\nA collection of space partitioning trees for Rust\n\n\u003c/div\u003e\n\n---\n\nSpart (**spa**ce **par**titioning **t**rees) is a Rust library that provides implementations of several\ncommon [space partitioning tree data structures](https://en.wikipedia.org/wiki/Space_partitioning) that can be used for\nindexing 2D and 3D point data to perform fast spatial queries, like k-nearest neighbor (kNN) and range search.\n\nThe library also includes Python bindings (see [pyspart](pyspart)), so it can easily be used in Python applications.\n\nAt the moment, the following tree data structures and features are supported:\n\n| # | Tree Type                                          | 2D | 3D | kNN Search | Radius Search |\n|---|----------------------------------------------------|:--:|:--:|:----------:|:-------------:|\n| 1 | [Quadtree](https://en.wikipedia.org/wiki/Quadtree) | ✓  |    |     ✓      |       ✓       |\n| 2 | [Octree](https://en.wikipedia.org/wiki/Octree)     |    | ✓  |     ✓      |       ✓       |\n| 3 | [Kd-tree](https://en.wikipedia.org/wiki/K-d_tree)  | ✓  | ✓  |     ✓      |       ✓       |\n| 4 | [R-tree](https://en.wikipedia.org/wiki/R-tree)     | ✓  | ✓  |     ✓      |       ✓       |\n| 5 | [R*-tree](https://en.wikipedia.org/wiki/R*-tree)   | ✓  | ✓  |     ✓      |       ✓       |\n\nSee the [ROADMAP.md](ROADMAP.md) for the list of implemented and planned features.\n\n\u003e [!IMPORTANT]\n\u003e Spart is in early development, so bugs and breaking changes are expected.\n\u003e Please use the [issues page](https://github.com/habedi/spart/issues) to report bugs or request features.\n\n---\n\n### Installation\n\n```bash\ncargo add spart\n````\n\n*Spart requires Rust 1.83.0 or later.*\n\n#### Python Bindings\n\nYou can install the Python bindings for Spart using `pip`:\n\n```shell\npip install pyspart\n```\n\nCheck out the [pyspart](pyspart) directory for more information about using Spart from Python.\n\n---\n\n### Documentation\n\nFor the Rust API documentation, see [docs.rs/spart](https://docs.rs/spart).\n\n#### Basic Concepts\n\nThe basic building blocks of Spart are **point** and **tree**.\n\n##### Point\n\nA point is a tuple of coordinates plus an optional data payload of any type.\nThere are two types of points: `Point2D` and `Point3D`.\n\nExample of 2D and 3D points:\n\n```rust\nuse spart::geometry::{Point2D, Point3D};\n\nfn main() {\n    // There are two ways to create a point.\n\n    // 1. Using the `new` method:\n    let point_2d = Point2D::new(1.0, 2.0, Some(\"A 2D Point\"));\n    let point_3d = Point3D::new(1.0, 2.0, 3.0, Some(\"A 3D Point\"));\n\n    // 2. Using a struct literal:\n    let point_2d_literal = Point2D {\n        x: 1.0,\n        y: 2.0,\n        data: Some(\"A 2D Point\"),\n    };\n    let point_3d_literal = Point3D {\n        x: 1.0,\n        y: 2.0,\n        z: 3.0,\n        data: Some(\"A 3D Point\"),\n    };\n}\n```\n\n##### Tree\n\nA tree is a spatial data structure that indexes points and provides methods for querying them.\n\nCurrently, the following trees are implemented:\n\n- Quadtree (2D)\n- Octree (3D)\n- Kd-tree (2D and 3D)\n- R-tree (2D and 3D)\n- R*-tree (2D and 3D)\n\nA tree provides at least the following methods:\n\n- `new`: creates a new tree given the following parameters:\n    - The bounding area of the tree (for Quadtree and Octree only)\n    - The number of dimensions (for Kd-tree only)\n    - The maximum capacity of points per node (for Quadtree, Octree, and R-tree)\n- `insert`: inserts a point into the tree.\n- `insert_bulk`: inserts multiple points into the tree at once.\n    - This is generally more efficient than inserting points one by one.\n- `delete`: removes a point from the tree.\n- `knn_search`: finds the k nearest neighbors to a query point.\n    - The inputs are the query point and the number of neighbors to find.\n- `range_search`: finds all points within a given range of a query point.\n    - The inputs are the query point and the range within which to search.\n\n\u003e [!NOTE]\n\u003e Currently, the following properties hold for all trees:\n\u003e - Duplicates are allowed: inserting a duplicate point will add another copy to the tree.\n\u003e - Searches return duplicates: both `knn_search` and `range_search` can return duplicate points if they were previously\n    inserted.\n\u003e - Deletion removes one instance: if there are duplicate points, the `delete` operation removes only one instance of\n    the point from the tree.\n\u003e - A `knn_search` with `k=0` will return an empty list.\n\u003e - A `knn_search` with `k` greater than the number of points in the tree will return all points.\n\u003e - A `range_search` with a radius of `0` will return only points with the exact same coordinates.\n\u003e\n\u003e The distance metric used for nearest neighbor and range searches is the Euclidean distance by default.\n\u003e However, you can use a custom distance metric by implementing the `DistanceMetric` trait.\n\u003e\n\u003e For example, here is how you can define and use the Manhattan distance:\n\u003e ```rust\n\u003e use spart::geometry::{Point2D, DistanceMetric};\n\u003e\n\u003e // 1. Define a struct for your distance metric.\n\u003e struct ManhattanDistance;\n\u003e\n\u003e // 2. Implement the `DistanceMetric` trait for your point type.\n\u003e impl\u003cT\u003e DistanceMetric\u003cPoint2D\u003cT\u003e\u003e for ManhattanDistance {\n\u003e     fn distance_sq(p1: \u0026Point2D\u003cT\u003e, p2: \u0026Point2D\u003cT\u003e) -\u003e f64 {\n\u003e         ((p1.x - p2.x).abs() + (p1.y - p2.y).abs()).powi(2)\n\u003e     }\n\u003e }\n\u003e\n\u003e // 3. Use it in a search function.\n\u003e // tree.knn_search::\u003cManhattanDistance\u003e(\u0026query_point, 1);\n\u003e ```\n\n#### Serialization\n\nSpart trees can be serialized and deserialized using the `serde` feature.\n\nTo enable serialization in Rust, you need to enable the `serde` feature in your `Cargo.toml` file:\n\n```toml\n[dependencies]\nspart = { version = \"0.3.0\", features = [\"serde\"] }\n```\n\nThen, you can use `bincode` (or any other serde-compatible library) to serialize and deserialize the tree.\nFor example, you can save and load a tree to and from a file:\n\n```rust\nuse spart::geometry::{Point2D, Rectangle};\nuse spart::quadtree::Quadtree;\nuse std::fs::File;\nuse std::io::{Read, Write};\n\nfn main() {\n    let boundary = Rectangle {\n        x: 0.0,\n        y: 0.0,\n        width: 100.0,\n        height: 100.0,\n    };\n    let mut qt = Quadtree::new(\u0026boundary, 4).unwrap();\n    qt.insert(Point2D::new(10.0, 20.0, Some(\"point1\".to_string())));\n    qt.insert(Point2D::new(50.0, 50.0, Some(\"point2\".to_string())));\n\n    // Serialize the tree to a file\n    let encoded: Vec\u003cu8\u003e = bincode::serialize(\u0026qt).unwrap();\n    let mut file = File::create(\"tree.spart\").unwrap();\n    file.write_all(\u0026encoded).unwrap();\n\n    // Deserialize the tree from a file\n    let mut file = File::open(\"tree.spart\").unwrap();\n    let mut encoded = Vec::new();\n    file.read_to_end(\u0026mut encoded).unwrap();\n    let decoded: Quadtree\u003cString\u003e = bincode::deserialize(\u0026encoded[..]).unwrap();\n}\n```\n\n#### Debugging Mode\n\nYou can enable debugging mode for Spart by setting the `DEBUG_SPART` environment variable to `true` or `1`.\n\n```bash\n# Enable debugging mode on Linux and macOS\nexport DEBUG_SPART=true\n```\n\n```powershell\n# Enable debugging mode on Windows (PowerShell)\n$env:DEBUG_SPART = \"true\"\n```\n\n\u003e [!NOTE]\n\u003e When debugging mode is enabled, Spart will be very verbose.\n\u003e It is recommended to use this only for debugging purposes.\n\n### Examples\n\n- For Rust examples, see the [examples](examples) directory.\n- For Python examples, see [pyspart/examples](pyspart/examples).\n\n---\n\n### Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to make a contribution.\n\n### License\n\nSpart is available under the terms of either of the following licenses:\n\n* MIT License ([LICENSE-MIT](LICENSE-MIT))\n* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))\n\n### Acknowledgements\n\n* The logo is from [SVG Repo](https://www.svgrepo.com/svg/382456/autumn-fall-leaf-orange-season-tree).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhabedi%2Fspart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhabedi%2Fspart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhabedi%2Fspart/lists"}