Skip to content

Commit 87bbca2

Browse files
export PackedRTree (#28)
* update headers * export packed rtree * export * test packed_rtree * ready to release * lint * lint * fix --------- Co-authored-by: TANG ZHIXIONG <zhixiong.tang@momenta.ai>
1 parent b06e682 commit 87bbca2

File tree

6 files changed

+113
-3
lines changed

6 files changed

+113
-3
lines changed

.github/workflows/wheels.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
with:
5050
platforms: all
5151

52-
- uses: pypa/cibuildwheel@v2.12.0
52+
- uses: pypa/cibuildwheel@v2.17.0
5353
env:
5454
# CIBW_ARCHS: auto64
5555
CIBW_ARCHS_LINUX: x86_64 aarch64

docs/about/release-notes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ To upgrade `pybind11-geobuf` to the latest version, use pip:
1010
pip install -U pybind11-geobuf
1111
```
1212

13+
## Version 0.2.1 (2024-03-14)
14+
15+
* Export PackedRTree
16+
1317
## Version 0.2.0 (2023-11-18)
1418

1519
* Indexing geobuf in protobuf format; Spec: geobuf_index.proto

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def build_extension(self, ext):
127127
# logic and declaration, and simpler if you include description/version in a file.
128128
setup(
129129
name="pybind11_geobuf",
130-
version="0.2.0",
130+
version="0.2.1",
131131
author="tzx",
132132
author_email="dvorak4tzx@gmail.com",
133133
url="https://geobuf-cpp.readthedocs.io",

src/main.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,69 @@ PYBIND11_MODULE(_pybind11_geobuf, m)
269269
auto geojson = m.def_submodule("geojson");
270270
cubao::bind_geojson(geojson);
271271

272+
using namespace FlatGeobuf;
273+
py::class_<NodeItem>(m, "NodeItem", py::module_local())
274+
.def_property_readonly("min_x",
275+
[](const NodeItem &self) { return self.minX; })
276+
.def_property_readonly("min_y",
277+
[](const NodeItem &self) { return self.minY; })
278+
.def_property_readonly("max_x",
279+
[](const NodeItem &self) { return self.maxX; })
280+
.def_property_readonly("max_y",
281+
[](const NodeItem &self) { return self.maxY; })
282+
.def_property_readonly("offset",
283+
[](const NodeItem &self) { return self.offset; })
284+
.def_property_readonly(
285+
"width", [](const NodeItem &self) { return self.width(); })
286+
.def_property_readonly(
287+
"height", [](const NodeItem &self) { return self.height(); })
288+
//
289+
.def("expand", &NodeItem::expand, "other"_a)
290+
.def("intersects", &NodeItem::intersects, "other"_a)
291+
.def(py::self == py::self)
292+
.def(py::self != py::self)
293+
.def("to_numpy",
294+
[](const NodeItem &self) -> Eigen::Vector4d {
295+
return {self.minX, self.minY, self.maxX, self.maxY};
296+
})
297+
//
298+
;
299+
300+
using PackedRTree = FlatGeobuf::PackedRTree;
301+
py::class_<PackedRTree>(m, "PackedRTree", py::module_local())
302+
.def(
303+
"search",
304+
[](const PackedRTree &self, double minX, double minY, double maxX,
305+
double maxY) {
306+
auto hits = self.search(minX, minY, maxX, maxY);
307+
std::vector<size_t> ret;
308+
ret.reserve(hits.size());
309+
for (auto &h : hits) {
310+
ret.push_back(h.offset);
311+
}
312+
return ret;
313+
},
314+
"min_x"_a, "min_y"_a, "max_x"_a, "max_y"_a)
315+
.def_property_readonly(
316+
"size", [](const PackedRTree &self) { return self.size(); })
317+
.def_property_readonly("extent",
318+
[](const PackedRTree &self) {
319+
auto bbox = self.getExtent();
320+
return Eigen::Vector4d(bbox.minX, bbox.minY,
321+
bbox.maxX, bbox.maxY);
322+
})
323+
.def_property_readonly(
324+
"num_items",
325+
[](const PackedRTree &self) { return self.getNumItems(); })
326+
.def_property_readonly(
327+
"num_nodes",
328+
[](const PackedRTree &self) { return self.getNumNodes(); })
329+
.def_property_readonly(
330+
"node_size",
331+
[](const PackedRTree &self) { return self.getNodeSize(); })
332+
//
333+
;
334+
272335
using Planet = cubao::Planet;
273336
py::class_<Planet>(m, "Planet", py::module_local())
274337
.def(py::init<>())
@@ -281,6 +344,7 @@ PYBIND11_MODULE(_pybind11_geobuf, m)
281344
.def("build", &Planet::build, py::kw_only(),
282345
"per_line_segment"_a = false, "force"_a = false)
283346
.def("query", &Planet::query, "min"_a, "max"_a)
347+
.def("packed_rtree", &Planet::packed_rtree, rvp::reference_internal)
284348
.def("copy", &Planet::copy)
285349
.def("crop", &Planet::crop, "polygon"_a, py::kw_only(),
286350
"clipping_mode"_a = "longest", //
@@ -303,6 +367,15 @@ PYBIND11_MODULE(_pybind11_geobuf, m)
303367
"offsets", [](const GeobufIndex &self) { return self.offsets; })
304368
.def_property_readonly("ids",
305369
[](const GeobufIndex &self) { return self.ids; })
370+
.def_property_readonly(
371+
"packed_rtree",
372+
[](const GeobufIndex &self) -> const FlatGeobuf::PackedRTree * {
373+
if (!self.packed_rtree) {
374+
return nullptr;
375+
}
376+
return &*self.packed_rtree;
377+
},
378+
rvp::reference_internal)
306379
//
307380
.def("init", py::overload_cast<const std::string &>(&GeobufIndex::init),
308381
"index_bytes"_a)

tests/test_geobuf.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,19 @@ def test_query():
18961896
path = f"{__pwd}/../data/suzhoubeizhan.pbf"
18971897
fc = geojson.FeatureCollection().load(path)
18981898
planet = Planet(fc)
1899+
1900+
tree = planet.packed_rtree()
1901+
assert id(tree) == id(planet.packed_rtree())
1902+
assert tree.extent.tolist() == [
1903+
120.623512,
1904+
31.4001743,
1905+
120.67509,
1906+
31.4458499,
1907+
]
1908+
assert tree.num_items == 1016
1909+
assert tree.num_nodes == 1085
1910+
assert tree.node_size == 16
1911+
18991912
hits = planet.query([120.64094, 31.41515], [120.64137, 31.41534])
19001913
assert len(hits) == 4
19011914
assert hits.tolist() == [529, 530, 536, 659]
@@ -1935,6 +1948,17 @@ def test_geobuf_index():
19351948
assert len(offsets) == 1018
19361949
assert offsets[:5] == [56, 318, 817, 999, 1174]
19371950
assert indexer.ids["24"] == 0
1951+
tree = indexer.packed_rtree
1952+
assert id(tree) == id(indexer.packed_rtree)
1953+
assert tree.extent.tolist() == [
1954+
120.623512,
1955+
31.4001743,
1956+
120.67509,
1957+
31.4458499,
1958+
]
1959+
assert tree.num_items == 1016
1960+
assert tree.num_nodes == 1085
1961+
assert tree.node_size == 16
19381962

19391963
expected = {
19401964
"type": "Feature",
@@ -2025,6 +2049,15 @@ def test_geobuf_index():
20252049

20262050
hits = indexer.query([120.64094, 31.41515], [120.64137, 31.41534])
20272051
assert len(hits) == 4
2052+
tree = indexer.packed_rtree
2053+
assert sorted(hits) == sorted(
2054+
tree.search(
2055+
120.64094,
2056+
31.41515,
2057+
120.64137,
2058+
31.41534,
2059+
)
2060+
)
20282061
hits = [indexer.decode_feature(h) for h in hits]
20292062
hits = [h.properties()["id"]() for h in hits]
20302063
assert hits == ["943", "936", "937", "1174"]

0 commit comments

Comments
 (0)