pybind: Add S2Cell bindings#631
Conversation
Binds S2Cell's constructors, factory methods, geometric accessors (vertex, edge, center, area), boundary helpers, containment and intersection predicates, and subdivide. Adds 43 unit tests. Distance methods and the S2Cap/S2LatLngRect-returning region methods are deferred with a TODO; they depend on S1ChordAngle/S2Cap/S2LatLngRect bindings which are not yet in place. (Stacked on deustis/s2cell_id_bindings / PR google#593.)
- Drop MaybeThrowNotValidCellId from S2Cell(S2CellId) constructor; all S2CellId objects reachable from Python are already validated - Remove instance average_area(); keep only static average_area_for_level() - Add S2CellId::kMaxPosition constant and validate pos in from_face_pos_level for both S2CellId and S2Cell bindings - Switch constants to cls.attr() pattern in both S2CellId and S2Cell bindings; update README to document this style - Fix BUILD: add absl/strings dep to s2cell_id_bindings - Remove misleading encode/decode comment from s2cell_bindings.cc - Fix magic constant 1<<30 -> 1<<S2CellId.MAX_LEVEL in s2cell_test.py
Consistent with other MaybeThrow* helpers in both binding files.
- Fix s2cell deps comment in module.cc to include s1chord_angle - Clarify orientation docstring (bitmask, values 0-3) - Drop _raw variants (vertex_raw, edge_raw, center_raw): Python callers don't feed unnormalized vectors into exact C++ predicates
|
@jmr, I've done a few rounds of self/LLM review here. Happy to make any changes as usual. |
| .def(py::self <= py::self, "Compare cells by their cell id") | ||
| .def(py::self >= py::self, "Compare cells by their cell id") | ||
| .def("__hash__", [](const S2Cell& self) { | ||
| return absl::Hash<S2CellId>()(self.id()); |
There was a problem hiding this comment.
use absl::HashOf(self). add include and deps
| "Return true if this is a leaf cell (level == kMaxLevel)") | ||
|
|
||
| // Geometric operations | ||
| .def("get_size_ij", &S2Cell::GetSizeIJ, |
There was a problem hiding this comment.
The get_ prefix should be removed in the python bindings. Add this to the readme and look for other places I forgot about this.
There was a problem hiding this comment.
Done. Also caught the same issue in s2cell_id_bindings.cc and s2latlng_bindings.cc (separate PR: deustis/drop_get_prefix). Added a note to README: "The Get prefix is dropped."
| }); | ||
|
|
||
| // Edge boundary constants (from S2Cell::Boundary enum). | ||
| cls.attr("BOTTOM_EDGE") = static_cast<int>(S2Cell::kBottomEdge); |
There was a problem hiding this comment.
Done. Used py::arithmetic() so existing integer comparisons still work.
|
|
||
| namespace { | ||
|
|
||
| void MaybeThrowFaceOutOfRange(int face) { |
| "Construct a leaf cell containing the given point.\n\n" | ||
| "The point does not need to be normalized.") | ||
| .def(py::init([](const S2LatLng& ll) { | ||
| return S2Cell(ll); |
There was a problem hiding this comment.
are all latlngs valid? i don't see the same comment as for cell id
There was a problem hiding this comment.
All S2LatLng objects reachable from Python are guaranteed valid. The bindings validate all constructors and factory methods and throw ValueError for out-of-range inputs. Added a comment matching the one on the S2CellId constructor.
| py::arg("point"), | ||
| "Construct a leaf cell containing the given point.\n\n" | ||
| "The point does not need to be normalized.") | ||
| .def(py::init([](const S2LatLng& ll) { |
There was a problem hiding this comment.
Look for functions with missing test coverage
There was a problem hiding this comment.
Added tests for all seven distance methods: distance (point), boundary_distance, max_distance (point), distance_to_edge, max_distance_to_edge, distance_to_cell, and max_distance_to_cell.
|
Tests are failing. |
- Drop get_ prefix from all Python method names across S2Cell, S2CellId, and S2LatLng bindings; document convention in README - Use py::enum_<S2Cell::Boundary> with py::arithmetic() instead of raw cls.attr() integer assignments - Use absl::HashOf in __hash__; add absl/hash include and BUILD dep - Add validity comment on S2LatLng constructor; comment duplicated helpers - Add tests for all seven distance methods on S2Cell
Fixed |
Adds pybind11 bindings for
S2Cell, covering constructors, factory methods, properties, geometric operations, containment/intersection tests, distance queries, and traversal.Naming:
GetDistanceis overloaded in C++ forS2Point, edge(a, b), andS2Cellarguments. Per the binding interface notes, the short name (get_distance) is used for theS2Pointoverload, and longer names (get_distance_to_edge,get_distance_to_cell) for the others.get_max_distancefollows the same pattern.Omitted::
_rawvariants:**vertex_raw,edge_raw, andcenter_rawreturn unnormalized vectors intended for feeding into exact C++ predicates. Python callers won't do that, so these are dropped in favor of the normalized versions.is_distance_less/is_distance_less_or_equalfamily is omitted — callers can useget_distance(...) < limitdirectly.get_cap_boundandget_rect_boundare deferred untilS2CapandS2LatLngRectare bound.Encode/Decodeare intentionally omitted per the serialization policy in the pybind README.(Part of a series addressing #522)
Test plan
bazel test //python/...— all suites pass.