Skip to content

Commit ff2ef0a

Browse files
author
peng.li24
committed
feat: update geometry_py.h, linestring.h, module.cpp, and tests
1 parent 52da825 commit ff2ef0a

5 files changed

Lines changed: 43 additions & 5 deletions

File tree

pycpp/geometry_py.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@ inline std::tuple<double,double> centroid_polygon(const Polygon<double>& p) { au
444444

445445
inline double project_ls_pt(const LineString<double>& l, const Point<double>& p) { return l.project(p); }
446446
inline std::tuple<double,double> interpolate_ls(const LineString<double>& l, double d) { auto r=l.interpolate(d); return {r.x,r.y}; }
447+
inline std::tuple<double,double> interpolate_ls_normalized(const LineString<double>& l, double t) {
448+
auto r = l.interpolate(t, true);
449+
return {r.x, r.y};
450+
}
447451

448452
inline double intersection_area_poly_poly(const Polygon<double>& p1, const Polygon<double>& p2) {
449453
return p1.intersection(p2).area();

shapely/geometry/linestring.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class LineString {
121121

122122
// -- Topology --
123123
template <typename U> double project(const Point<U>& other) const;
124-
Point<double> interpolate(double distance) const;
124+
Point<double> interpolate(double distance, bool normalized = false) const;
125125
Point<double> centroid() const;
126126
Polygon<double> buffer(double distance) const;
127127

@@ -344,9 +344,17 @@ double LineString<T>::project(const Point<U>& o) const {
344344

345345
// Python: base.py::interpolate:L915
346346
template <typename T>
347-
Point<double> LineString<T>::interpolate(double distance) const {
347+
Point<double> LineString<T>::interpolate(double distance, bool normalized) const {
348+
double abs_dist;
349+
if (normalized) {
350+
if (distance < 0.0) distance = 0.0;
351+
if (distance > 1.0) distance = 1.0;
352+
abs_dist = distance * this->length();
353+
} else {
354+
abs_dist = distance;
355+
}
348356
geos::linearref::LengthIndexedLine lil(geos_linestring_.get());
349-
auto c = lil.extractPoint(distance);
357+
auto c = lil.extractPoint(abs_dist);
350358
return Point<double>(c.x, c.y);
351359
}
352360

tests/module.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,9 @@ PYBIND11_MODULE(shapelycpp, m) {
387387
// ======================================================================
388388
// Project / interpolate (from pycpp)
389389
// ======================================================================
390-
m.def("project_linestring_point", &project_ls_pt);
391-
m.def("interpolate_linestring", &interpolate_ls);
390+
m.def("project_linestring_point", &project_ls_pt);
391+
m.def("interpolate_linestring", &interpolate_ls);
392+
m.def("interpolate_linestring_normalized", &interpolate_ls_normalized);
392393

393394
// ======================================================================
394395
// Intersection area (from pycpp)

tests/report.csv

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ ops,interpolate_linestring,unknown,f64,v_mid,PASS,0
230230
ops,interpolate_linestring,unknown,f64,h_start,PASS,0
231231
ops,interpolate_linestring,unknown,f64,h_end,PASS,0
232232
ops,interpolate_linestring,unknown,f64,v3pt,PASS,0
233+
ops,interpolate_linestring_normalized,unknown,f64,h_mid,PASS,0
234+
ops,interpolate_linestring_normalized,unknown,f64,h_start,PASS,0
235+
ops,interpolate_linestring_normalized,unknown,f64,h_end,PASS,0
236+
ops,interpolate_linestring_normalized,unknown,f64,v_mid,PASS,0
237+
ops,interpolate_linestring_normalized,unknown,f64,v3pt_end,PASS,0
233238
ops,centroid_point,unknown,f64,3-4,PASS,0
234239
ops,centroid_point,unknown,f64,neg,PASS,0
235240
ops,centroid_linestring,unknown,f64,d,PASS,0

tests/test_all.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ def _compare_bit_exact(cpp_result, py_result, label=""):
147147
_OPS_NAMES = {
148148
"centroid_point", "centroid_linestring", "centroid_polygon",
149149
"project_linestring_point", "interpolate_linestring",
150+
"interpolate_linestring_normalized",
150151
"intersection_area_polygon_polygon",
151152
"polygon_exterior",
152153
"nearest_points", "nearest_points_ls_pt",
@@ -356,6 +357,14 @@ def _call_ops(api_name, cpp, *args, **kwargs):
356357
py_pt = py_ls.interpolate(dist)
357358
return np.array(c_result), np.array((py_pt.x, py_pt.y))
358359

360+
if api_name == "interpolate_linestring_normalized":
361+
c_ls = _build_cpp_geom(cpp, *geoms[0])
362+
py_ls = _build_py_geom(*geoms[0])
363+
t = float(extras[0]) if extras else 0.5
364+
c_result = cpp.interpolate_linestring_normalized(c_ls, t)
365+
py_pt = py_ls.interpolate(t, normalized=True)
366+
return np.array(c_result), np.array((py_pt.x, py_pt.y))
367+
359368
if api_name == "intersection_area_polygon_polygon":
360369
c_a = _build_cpp_geom(cpp, *geoms[0])
361370
c_b = _build_cpp_geom(cpp, *geoms[1])
@@ -879,6 +888,17 @@ def _catalog_ops():
879888
yield _TestCase("interpolate_linestring", (ls, dist), {}, "f64", tag,
880889
"bit_exact", True, None, "ops")
881890

891+
# -- interpolate_linestring_normalized --
892+
for ls, t, py_t_expected_tag, tag in [
893+
(("ls", _L_H), 0.5, "h_mid", "h_mid"), # t=0.5 → midpoint of 10-length horizontal
894+
(("ls", _L_H), 0.0, "h_start", "h_start"), # t=0.0 → start
895+
(("ls", _L_H), 1.0, "h_end", "h_end"), # t=1.0 → end
896+
(("ls", _L_V), 0.5, "v_mid", "v_mid"), # vertical 10-length, t=0.5
897+
(("ls", _L_3), 1.0, "v3pt", "v3pt_end"), # 3-point L, t=1.0
898+
]:
899+
yield _TestCase("interpolate_linestring_normalized", (ls, t), {},
900+
"f64", tag, "bit_exact", True, None, "ops")
901+
882902
# -- Centroid --
883903
for name, geom, tag in [
884904
("centroid_point", ("pt", (3, 4)), "3-4"),

0 commit comments

Comments
 (0)