Skip to content

Commit db65c20

Browse files
author
peng.li24
committed
refactor(pycpp): move thin wrappers into shapely_py::detail namespace
1 parent a90ae07 commit db65c20

1 file changed

Lines changed: 49 additions & 51 deletions

File tree

pycpp/geometry_py.h

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ using namespace shapely::geometry;
3232
namespace shapely_py {
3333

3434
// ============================================================================
35-
// Internal helpers
35+
// Internal helpers — hidden in detail namespace
3636
// ============================================================================
37+
namespace detail {
3738

3839
/// Copy native T* data to a Python numpy array.
3940
template <typename T>
@@ -99,6 +100,8 @@ inline std::vector<double> array_to_double_vec(const py::array& arr) {
99100
return tmp;
100101
}
101102

103+
} // namespace detail
104+
102105
// ============================================================================
103106
// Factory functions — all overloaded, no _f32 suffixes
104107
// ============================================================================
@@ -109,14 +112,14 @@ inline Point<float> point(float x, float y) { return Point<float>(x, y); }
109112

110113
inline Point<double> point(const py::array_t<double>& arr) {
111114
auto buf = arr.request();
112-
ensure_c_contiguous(buf);
115+
detail::ensure_c_contiguous(buf);
113116
const double* p = static_cast<const double*>(buf.ptr);
114117
return Point<double>(buf.size > 0 ? p[0] : 0, buf.size > 1 ? p[1] : 0);
115118
}
116119
// float32 auto-upcast: prevent GEOS precision mismatch vs Python shapely
117120
inline Point<double> point(const py::array_t<float>& arr) {
118121
auto buf = arr.request();
119-
ensure_c_contiguous(buf);
122+
detail::ensure_c_contiguous(buf);
120123
const float* p = static_cast<const float*>(buf.ptr);
121124
return Point<double>(buf.size > 0 ? static_cast<double>(p[0]) : 0,
122125
buf.size > 1 ? static_cast<double>(p[1]) : 0);
@@ -125,7 +128,7 @@ inline Point<double> point(const py::array_t<float>& arr) {
125128
// Handles 1D [x,y] and 2D (N,≥2) arrays — takes first 2 elements.
126129
inline Point<double> point(const py::array& arr) {
127130
auto buf = arr.request();
128-
ensure_c_contiguous(buf);
131+
detail::ensure_c_contiguous(buf);
129132
if (buf.size < 2) return Point<double>(0, 0);
130133
if (arr.dtype().is(py::dtype::of<double>())) {
131134
const double* p = static_cast<const double*>(buf.ptr);
@@ -142,18 +145,18 @@ inline Point<double> point(const py::array& arr) {
142145
// -- LineString --
143146
inline LineString<double> linestring(const py::array_t<double>& arr) {
144147
auto buf = arr.request();
145-
ensure_c_contiguous(buf);
148+
detail::ensure_c_contiguous(buf);
146149
return LineString<double>(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
147150
}
148151
// float32 auto-upcast: prevent GEOS precision mismatch vs Python shapely
149152
inline LineString<double> linestring(const py::array_t<float>& arr) {
150153
py::ssize_t n = arr.request().shape[0];
151-
auto tmp = array_to_double_vec(arr);
154+
auto tmp = detail::array_to_double_vec(arr);
152155
return LineString<double>(tmp.data(), static_cast<size_t>(n), 2);
153156
}
154157
inline LineString<double> linestring(const py::array& arr) {
155158
py::ssize_t n = arr.request().shape[0];
156-
auto tmp = array_to_double_vec(arr);
159+
auto tmp = detail::array_to_double_vec(arr);
157160
return LineString<double>(tmp.data(), static_cast<size_t>(n), 2);
158161
}
159162

@@ -173,48 +176,48 @@ inline LineString<double> linestring(const std::vector<std::array<double, 2>>& p
173176
// -- Polygon --
174177
inline Polygon<double> polygon(const py::array_t<double>& arr) {
175178
auto buf = arr.request();
176-
ensure_c_contiguous(buf);
179+
detail::ensure_c_contiguous(buf);
177180
return Polygon<double>(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
178181
}
179182
// float32 auto-upcast: prevent GEOS precision mismatch vs Python shapely
180183
inline Polygon<double> polygon(const py::array_t<float>& arr) {
181184
py::ssize_t n = arr.request().shape[0];
182-
auto tmp = array_to_double_vec(arr);
185+
auto tmp = detail::array_to_double_vec(arr);
183186
return Polygon<double>(tmp.data(), static_cast<size_t>(n), 2);
184187
}
185188
inline Polygon<double> polygon(const py::array& arr) {
186189
py::ssize_t n = arr.request().shape[0];
187-
auto tmp = array_to_double_vec(arr);
190+
auto tmp = detail::array_to_double_vec(arr);
188191
return Polygon<double>(tmp.data(), static_cast<size_t>(n), 2);
189192
}
190193

191194
// -- LinearRing (double only for now) --
192195
inline LinearRing<double> linearring(const py::array_t<double>& arr) {
193196
auto buf = arr.request();
194-
ensure_c_contiguous(buf);
197+
detail::ensure_c_contiguous(buf);
195198
return LinearRing<double>(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
196199
}
197200
inline LinearRing<double> linearring(const py::array& arr) {
198201
py::ssize_t n = arr.request().shape[0];
199-
auto tmp = array_to_double_vec(arr);
202+
auto tmp = detail::array_to_double_vec(arr);
200203
return LinearRing<double>(tmp.data(), static_cast<size_t>(n), 2);
201204
}
202205

203206
// -- MultiPoint: single array of shape (n_pts, 2) --
204207
inline MultiPoint<double> multipoint(const py::array_t<double>& arr) {
205208
auto buf = arr.request();
206-
ensure_c_contiguous(buf);
209+
detail::ensure_c_contiguous(buf);
207210
return MultiPoint<double>(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
208211
}
209212
// float32 auto-upcast: prevent GEOS precision mismatch vs Python shapely
210213
inline MultiPoint<double> multipoint(const py::array_t<float>& arr) {
211214
py::ssize_t n = arr.request().shape[0];
212-
auto tmp = array_to_double_vec(arr);
215+
auto tmp = detail::array_to_double_vec(arr);
213216
return MultiPoint<double>(tmp.data(), static_cast<size_t>(n), 2);
214217
}
215218
inline MultiPoint<double> multipoint(const py::array& arr) {
216219
py::ssize_t n = arr.request().shape[0];
217-
auto tmp = array_to_double_vec(arr);
220+
auto tmp = detail::array_to_double_vec(arr);
218221
return MultiPoint<double>(tmp.data(), static_cast<size_t>(n), 2);
219222
}
220223

@@ -223,7 +226,7 @@ inline MultiLineString<double> multilinestring(const std::vector<py::array_t<dou
223226
MultiLineString<double> mls;
224227
for (auto& arr : arrays) {
225228
auto buf = arr.request();
226-
ensure_c_contiguous(buf);
229+
detail::ensure_c_contiguous(buf);
227230
mls.add_line(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
228231
}
229232
return mls;
@@ -233,7 +236,7 @@ inline MultiLineString<double> multilinestring(const std::vector<py::array_t<flo
233236
MultiLineString<double> mls;
234237
for (auto& arr : arrays) {
235238
py::ssize_t n = arr.request().shape[0];
236-
auto tmp = array_to_double_vec(arr);
239+
auto tmp = detail::array_to_double_vec(arr);
237240
mls.add_line(tmp.data(), static_cast<size_t>(n), 2);
238241
}
239242
return mls;
@@ -242,7 +245,7 @@ inline MultiLineString<double> multilinestring(const std::vector<py::array>& arr
242245
MultiLineString<double> mls;
243246
for (auto& arr : arrays) {
244247
py::ssize_t n = arr.request().shape[0];
245-
auto tmp = array_to_double_vec(arr);
248+
auto tmp = detail::array_to_double_vec(arr);
246249
mls.add_line(tmp.data(), static_cast<size_t>(n), 2);
247250
}
248251
return mls;
@@ -253,7 +256,7 @@ inline MultiPolygon<double> multipolygon(const std::vector<py::array_t<double>>&
253256
MultiPolygon<double> mp;
254257
for (auto& arr : arrays) {
255258
auto buf = arr.request();
256-
ensure_c_contiguous(buf);
259+
detail::ensure_c_contiguous(buf);
257260
mp.add_polygon(static_cast<const double*>(buf.ptr), buf.shape[0], buf.shape[1]);
258261
}
259262
return mp;
@@ -263,7 +266,7 @@ inline MultiPolygon<double> multipolygon(const std::vector<py::array_t<float>>&
263266
MultiPolygon<double> mp;
264267
for (auto& arr : arrays) {
265268
py::ssize_t n = arr.request().shape[0];
266-
auto tmp = array_to_double_vec(arr);
269+
auto tmp = detail::array_to_double_vec(arr);
267270
mp.add_polygon(tmp.data(), static_cast<size_t>(n), 2);
268271
}
269272
return mp;
@@ -272,32 +275,33 @@ inline MultiPolygon<double> multipolygon(const std::vector<py::array>& arrays) {
272275
MultiPolygon<double> mp;
273276
for (auto& arr : arrays) {
274277
py::ssize_t n = arr.request().shape[0];
275-
auto tmp = array_to_double_vec(arr);
278+
auto tmp = detail::array_to_double_vec(arr);
276279
mp.add_polygon(tmp.data(), static_cast<size_t>(n), 2);
277280
}
278281
return mp;
279282
}
280283

281284
// ============================================================================
282-
// Cross-type distance
285+
// Cross-type wrappers (distance, intersects, predicates, centroid, etc.)
286+
// Thin wrappers that bridge pybind11's cross-type dispatch limitation.
287+
// Hidden in detail — downstream code should use shapely::geometry methods directly.
283288
// ============================================================================
289+
namespace detail {
290+
291+
// -- Cross-type distance --
284292

285293
inline double distance_pt_ls(const Point<double>& p, const LineString<double>& l) { return p.distance(l); }
286294
inline double distance_pt_poly(const Point<double>& p, const Polygon<double>& poly) { return p.distance(poly); }
287295
inline double distance_ls_poly(const LineString<double>& l, const Polygon<double>& poly) { return l.distance(poly); }
288296
inline double distance_poly_ls(const Polygon<double>& poly, const LineString<double>& l) { return poly.distance(l); }
289297

290-
// ============================================================================
291-
// Cross-type intersects
292-
// ============================================================================
298+
// -- Cross-type intersects --
293299

294300
inline bool intersects_ls_poly(const LineString<double>& l, const Polygon<double>& poly) { return l.intersects(poly); }
295301
inline bool intersects_poly_ls(const Polygon<double>& poly, const LineString<double>& l) { return poly.intersects(l); }
296302
inline bool intersects_poly_poly(const Polygon<double>& p1, const Polygon<double>& p2) { return p1.intersects(p2); }
297303

298-
// ============================================================================
299-
// Predicates — all 9 cross-type pairs
300-
// ============================================================================
304+
// -- Predicates — all 9 cross-type pairs --
301305

302306
// -- Point ↔ Point --
303307
inline bool pt_contains_pt(const Point<double>& s, const Point<double>& o) { return s.contains(o); }
@@ -434,50 +438,44 @@ inline bool poly_intersects_poly(const Polygon<double>& s, const Polygon<double>
434438
inline std::string poly_relate_poly(const Polygon<double>& s, const Polygon<double>& o) { return s.relate(o); }
435439
inline double poly_hausdorff_distance_poly(const Polygon<double>& s, const Polygon<double>& o) { return s.hausdorff_distance(o); }
436440

437-
// ============================================================================
438-
// Centroid, project, interpolate
439-
// ============================================================================
441+
// -- Centroid --
440442

441443
inline std::tuple<double,double> centroid_point(const Point<double>& p) { auto r=p.centroid(); return {r.x,r.y}; }
442444
inline std::tuple<double,double> centroid_linestring(const LineString<double>& l) { auto r=l.centroid(); return {r.x,r.y}; }
443445
inline std::tuple<double,double> centroid_polygon(const Polygon<double>& p) { auto r=p.centroid(); return {r.x,r.y}; }
444446

445-
inline double project_ls_pt(const LineString<double>& l, const Point<double>& p) { return l.project(p); }
446-
inline std::tuple<double,double> interpolate_ls(const LineString<double>& l, double d, bool normalized = false) {
447-
auto r = l.interpolate(d, normalized);
448-
return {r.x, r.y};
449-
}
450-
451447
inline double intersection_area_poly_poly(const Polygon<double>& p1, const Polygon<double>& p2) {
452448
return p1.intersection(p2).area();
453449
}
454450

455451
inline py::array_t<double> polygon_exterior(const Polygon<double>& p) {
456452
auto ext = p.exterior();
457-
return native_to_array(ext.data(), ext.rows(), ext.cols());
453+
return detail::native_to_array(ext.data(), ext.rows(), ext.cols());
458454
}
459455

456+
} // namespace detail
457+
460458
} // namespace shapely_py
461459

462460
// ============================================================================
463461
// Pybind11 binding helper macros
464462
// ============================================================================
465463

466464
#define BIND_PREDS(m, SRC, TGT) \
467-
m.def(#SRC "_contains_" #TGT, &shapely_py::SRC ## _contains_ ## TGT); \
468-
m.def(#SRC "_within_" #TGT, &shapely_py::SRC ## _within_ ## TGT); \
469-
m.def(#SRC "_crosses_" #TGT, &shapely_py::SRC ## _crosses_ ## TGT); \
470-
m.def(#SRC "_disjoint_" #TGT, &shapely_py::SRC ## _disjoint_ ## TGT); \
471-
m.def(#SRC "_overlaps_" #TGT, &shapely_py::SRC ## _overlaps_ ## TGT); \
472-
m.def(#SRC "_touches_" #TGT, &shapely_py::SRC ## _touches_ ## TGT); \
473-
m.def(#SRC "_covers_" #TGT, &shapely_py::SRC ## _covers_ ## TGT); \
474-
m.def(#SRC "_covered_by_" #TGT, &shapely_py::SRC ## _covered_by_ ## TGT); \
475-
m.def(#SRC "_equals_" #TGT, &shapely_py::SRC ## _equals_ ## TGT); \
476-
m.def(#SRC "_equals_exact_" #TGT, &shapely_py::SRC ## _equals_exact_ ## TGT, \
465+
m.def(#SRC "_contains_" #TGT, &shapely_py::detail::SRC ## _contains_ ## TGT); \
466+
m.def(#SRC "_within_" #TGT, &shapely_py::detail::SRC ## _within_ ## TGT); \
467+
m.def(#SRC "_crosses_" #TGT, &shapely_py::detail::SRC ## _crosses_ ## TGT); \
468+
m.def(#SRC "_disjoint_" #TGT, &shapely_py::detail::SRC ## _disjoint_ ## TGT); \
469+
m.def(#SRC "_overlaps_" #TGT, &shapely_py::detail::SRC ## _overlaps_ ## TGT); \
470+
m.def(#SRC "_touches_" #TGT, &shapely_py::detail::SRC ## _touches_ ## TGT); \
471+
m.def(#SRC "_covers_" #TGT, &shapely_py::detail::SRC ## _covers_ ## TGT); \
472+
m.def(#SRC "_covered_by_" #TGT, &shapely_py::detail::SRC ## _covered_by_ ## TGT); \
473+
m.def(#SRC "_equals_" #TGT, &shapely_py::detail::SRC ## _equals_ ## TGT); \
474+
m.def(#SRC "_equals_exact_" #TGT, &shapely_py::detail::SRC ## _equals_exact_ ## TGT, \
477475
py::arg("self"), py::arg("other"), py::arg("tolerance")); \
478-
m.def(#SRC "_intersects_" #TGT, &shapely_py::SRC ## _intersects_ ## TGT); \
479-
m.def(#SRC "_relate_" #TGT, &shapely_py::SRC ## _relate_ ## TGT); \
480-
m.def(#SRC "_hausdorff_distance_" #TGT, &shapely_py::SRC ## _hausdorff_distance_ ## TGT);
476+
m.def(#SRC "_intersects_" #TGT, &shapely_py::detail::SRC ## _intersects_ ## TGT); \
477+
m.def(#SRC "_relate_" #TGT, &shapely_py::detail::SRC ## _relate_ ## TGT); \
478+
m.def(#SRC "_hausdorff_distance_" #TGT, &shapely_py::detail::SRC ## _hausdorff_distance_ ## TGT);
481479

482480
#define BIND_ACCESSORS(CLS) \
483481
.def("wkt", &CLS::wkt) \

0 commit comments

Comments
 (0)