Skip to content

Commit

Permalink
more binding (#9)
Browse files Browse the repository at this point in the history
* misc update

* add hsv to rgb, random stroke

* next rgb

* assert randoms

* clear ubodt

* match, lots of work to do

* more types

* fix build

* more bindings from nano-fmm

* some code from geobuf-cpp

* misc

* fix

* test edge case

---------

Co-authored-by: TANG ZHIXIONG <[email protected]>
  • Loading branch information
district10 and zhixiong-tang authored Aug 29, 2023
1 parent 052b760 commit 3844783
Show file tree
Hide file tree
Showing 18 changed files with 1,321 additions and 66 deletions.
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@
"regex": "cpp",
"future": "cpp",
"__bits": "cpp",
"bit": "cpp"
"bit": "cpp",
"charconv": "cpp",
"concepts": "cpp",
"memory_resource": "cpp",
"ranges": "cpp",
"stop_token": "cpp"
},
"workbench.colorCustomizations": {
// "activityBar.background": "#b80ae3",
Expand Down
145 changes: 145 additions & 0 deletions src/bindings/pybind11_helpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#pragma once

// migrated from
// https://github.com/cubao/geobuf-cpp/blob/dev/src/geobuf/pybind11_helpers.hpp

#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

#include "nano_fmm/types.hpp"
#include "nano_fmm/rapidjson_helpers.hpp"

namespace nano_fmm
{
namespace py = pybind11;
using namespace pybind11::literals;
using rvp = py::return_value_policy;

inline RapidjsonValue __py_int_to_rapidjson(const py::handle &obj)
{
try {
auto num = obj.cast<int64_t>();
if (py::int_(num).equal(obj)) {
return RapidjsonValue(num);
}
} catch (...) {
}
try {
auto num = obj.cast<uint64_t>();
if (py::int_(num).equal(obj)) {
return RapidjsonValue(num);
}
} catch (...) {
}
throw std::runtime_error(
"failed to convert to rapidjson, invalid integer: " +
py::repr(obj).cast<std::string>());
}

inline RapidjsonValue to_rapidjson(const py::handle &obj,
RapidjsonAllocator &allocator)
{
if (obj.ptr() == nullptr || obj.is_none()) {
return {};
}
if (py::isinstance<py::bool_>(obj)) {
return RapidjsonValue(obj.cast<bool>());
}
if (py::isinstance<py::int_>(obj)) {
return __py_int_to_rapidjson(obj);
}
if (py::isinstance<py::float_>(obj)) {
return RapidjsonValue(obj.cast<double>());
}
if (py::isinstance<py::bytes>(obj)) {
// https://github.com/pybind/pybind11_json/blob/master/include/pybind11_json/pybind11_json.hpp#L112
py::module base64 = py::module::import("base64");
auto str = base64.attr("b64encode")(obj)
.attr("decode")("utf-8")
.cast<std::string>();
return RapidjsonValue(str.data(), str.size(), allocator);
}
if (py::isinstance<py::str>(obj)) {
auto str = obj.cast<std::string>();
return RapidjsonValue(str.data(), str.size(), allocator);
}
if (py::isinstance<py::tuple>(obj) || py::isinstance<py::list>(obj)) {
RapidjsonValue arr(rapidjson::kArrayType);
for (const py::handle &value : obj) {
arr.PushBack(to_rapidjson(value, allocator), allocator);
}
return arr;
}
if (py::isinstance<py::dict>(obj)) {
RapidjsonValue kv(rapidjson::kObjectType);
for (const py::handle &key : obj) {
auto k = py::str(key).cast<std::string>();
kv.AddMember(RapidjsonValue(k.data(), k.size(), allocator),
to_rapidjson(obj[key], allocator), allocator);
}
return kv;
}
if (py::isinstance<RapidjsonValue>(obj)) {
auto ptr = py::cast<const RapidjsonValue *>(obj);
return deepcopy(*ptr, allocator);
}
throw std::runtime_error(
"to_rapidjson not implemented for this type of object: " +
py::repr(obj).cast<std::string>());
}

inline RapidjsonValue to_rapidjson(const py::handle &obj)
{
RapidjsonAllocator allocator;
return to_rapidjson(obj, allocator);
}

inline py::object to_python(const RapidjsonValue &j)
{
if (j.IsNull()) {
return py::none();
} else if (j.IsBool()) {
return py::bool_(j.GetBool());
} else if (j.IsNumber()) {
if (j.IsUint64()) {
return py::int_(j.GetUint64());
} else if (j.IsInt64()) {
return py::int_(j.GetInt64());
} else {
return py::float_(j.GetDouble());
}
} else if (j.IsString()) {
return py::str(std::string{j.GetString(), j.GetStringLength()});
} else if (j.IsArray()) {
py::list ret;
for (const auto &e : j.GetArray()) {
ret.append(to_python(e));
}
return ret;
} else {
py::dict ret;
for (auto &m : j.GetObject()) {
ret[py::str(
std::string{m.name.GetString(), m.name.GetStringLength()})] =
to_python(m.value);
}
return ret;
}
}
} // namespace nano_fmm

#ifndef BIND_PY_FLUENT_ATTRIBUTE
#define BIND_PY_FLUENT_ATTRIBUTE(Klass, type, var) \
.def( \
#var, [](Klass &self) -> type & { return self.var; }, \
rvp::reference_internal) \
.def( \
#var, \
[](Klass &self, const type &v) -> Klass & { \
self.var = v; \
return self; \
}, \
rvp::reference_internal)
#endif
52 changes: 38 additions & 14 deletions src/bindings/pybind11_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@ using rvp = py::return_value_policy;
void bind_network(py::module &m)
{
py::class_<ProjectedPoint>(m, "ProjectedPoint", py::module_local()) //
.def(py::init<const Eigen::Vector3d &, double, int64_t, double>(),
"position"_a = Eigen::Vector3d(0, 0, 0), "distance"_a = 0.0,
"road_id"_a = 0, "offset"_a = 0.0)
.def(py::init<const Eigen::Vector3d &, //
const Eigen::Vector3d &, //
double, //
int64_t, //
double>(),
py::kw_only(), //
"position"_a = Eigen::Vector3d(0, 0, 0), //
"direction"_a = Eigen::Vector3d(0, 0, 1), //
"distance"_a = 0.0, //
"road_id"_a = 0, //
"offset"_a = 0.0)
//
.def_property_readonly(
"position",
[](const ProjectedPoint &self) { return self.position_; })
.def_property_readonly(
"direction",
[](const ProjectedPoint &self) { return self.direction_; })
.def_property_readonly(
"distance",
[](const ProjectedPoint &self) { return self.distance_; })
Expand All @@ -34,24 +45,30 @@ void bind_network(py::module &m)
;

py::class_<UbodtRecord>(m, "UbodtRecord", py::module_local()) //
.def(py::init<>())
.def(py::init<int64_t, int64_t, int64_t, int64_t, double>(),
py::kw_only(),
"source_road"_a = 0, //
"target_road"_a = 0, //
"source_next"_a = 0, //
"target_prev"_a = 0, //
"cost"_a = 0.0)
//
.def_property_readonly(
"source_road",
[](const UbodtRecord &self) { return self.source_road; })
[](const UbodtRecord &self) { return self.source_road_; })
.def_property_readonly(
"target_road",
[](const UbodtRecord &self) { return self.target_road; })
[](const UbodtRecord &self) { return self.target_road_; })
.def_property_readonly(
"source_next",
[](const UbodtRecord &self) { return self.source_next; })
[](const UbodtRecord &self) { return self.source_next_; })
.def_property_readonly(
"target_prev",
[](const UbodtRecord &self) { return self.target_prev; })
[](const UbodtRecord &self) { return self.target_prev_; })
.def_property_readonly(
"cost", [](const UbodtRecord &self) { return self.cost; })
"cost", [](const UbodtRecord &self) { return self.cost_; })
.def_property_readonly(
"next", [](const UbodtRecord &self) { return self.next; },
"next", [](const UbodtRecord &self) { return self.next_; },
rvp::reference_internal)
//
.def(py::self == py::self)
Expand All @@ -60,9 +77,9 @@ void bind_network(py::module &m)
.def("__repr__", [](const UbodtRecord &self) {
return fmt::format(
"UbodtRecord(s->t=[{}->{}], cost:{}, sn:{},tp:{})",
self.source_road, self.target_road, //
self.cost, //
self.source_next, self.target_prev);
self.source_road_, self.target_road_, //
self.cost_, //
self.source_next_, self.target_prev_);
});
//
;
Expand Down Expand Up @@ -112,7 +129,14 @@ void bind_network(py::module &m)
std::optional<double>>(&Network::build_ubodt,
py::const_),
"roads"_a, py::kw_only(), "thresh"_a = std::nullopt)
.def("load_ubodt", &Network::load_ubodt, "path"_a)
.def("clear_ubodt", &Network::clear_ubodt)
.def("load_ubodt",
py::overload_cast<const std::vector<UbodtRecord> &>(
&Network::load_ubodt),
"rows"_a)
.def("load_ubodt",
py::overload_cast<const std::string &>(&Network::load_ubodt),
"path"_a)
.def("dump_ubodt", &Network::dump_ubodt, "path"_a, py::kw_only(),
"thresh"_a = std::nullopt)
//
Expand Down
31 changes: 31 additions & 0 deletions src/bindings/pybind11_randoms.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <pybind11/eigen.h>
#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

#include "nano_fmm/randoms.hpp"

namespace nano_fmm
{
namespace py = pybind11;
using namespace pybind11::literals;
using rvp = py::return_value_policy;

void bind_randoms(py::module &m)
{
m //
.def("hsv2rgb", &hsv_to_rgb, "h"_a, "s"_a, "v"_a)
//
;
py::class_<RandomColor>(m, "RandomColor", py::module_local()) //
.def(py::init<bool>(), py::kw_only(), "on_black"_a = true)
.def(py::init<int, bool>(), "seed"_a, py::kw_only(),
"on_black"_a = true)
//
.def("next_rgb", &RandomColor::next_rgb)
.def("next_hex", &RandomColor::next_hex)
//
;
}
} // namespace nano_fmm
Loading

0 comments on commit 3844783

Please sign in to comment.