It took me some time to figure out the issues like
"ImportError: generic_type: type "VertexProperty_easy3d_PolyMesh_VertexConnectivity_t" referenced unknown base type "easy3d::Property<easy3d::PolyMesh::VertexConnectivity>"
It seems in the bindings code, the order of the definition of the types matters. The solution is quite straight forward.
You will see
struct PyCallBack_easy3d_Property_easy3d_PolyMesh_VertexConnectivity_t : public easy3d::Property<easy3d::PolyMesh::VertexConnectivity> { ... }
and
pybind11::class_<easy3d::Property<easy3d::PolyMesh::VertexConnectivity>, std::shared_ptr<easy3d::Property<easy3d::PolyMesh::VertexConnectivity>>, PyCallBack_easy3d_Property_easy3d_PolyMesh_VertexConnectivity_t> cl(m, "Property_easy3d_PolyMesh_VertexConnectivity_t", "");
Just put the definition of
"Property_easy3d_PolyMesh_VertexConnectivity_t"
before
"VertexProperty_easy3d_PolyMesh_VertexConnectivity_t"
The error occurs because pybind11 requires that a base class (easy3d::Model) is registered before a derived class (easy3d::Graph).
If the derived class is registered before the base class, it results in the "unknown base type" error.
Issues with C++ reference as argument.
In C++, your function signature modifies the squared_distance argument directly because it is passed by reference (float &).
However, Python doesn’t have the concept of pass-by-reference in the same way. In Pybind11, you must explicitly wrap such arguments to achieve the desired behavior.
cl.def("find_closest_point",
[](const easy3d::KdTreeSearch_ANN &self, const easy3d::vec3 &p) {
return self.find_closest_point(p);
},
"Queries the closest point for a given point (without returning squared distance)",
pybind11::arg("p"));
cl.def("find_closest_point_with_squared_distance",
[](const easy3d::KdTreeSearch_ANN &self, const easy3d::vec3 &p) {
float squared_distance = 0.0f;
int result = self.find_closest_point(p, squared_distance);
return std::make_pair(result, squared_distance);
},
"Queries the closest point for a given point (returns squared distance as well)",
pybind11::arg("p"));
Instead of exposing the original find_closest_point directly, a lambda function is used as a wrapper. Inside this wrapper:
A temporary variable squared_distance is created to store the output.
The original find_closest_point function is called, modifying squared_distance.
The result is returned as a std::pair<int, float>.
In Python, you can now return both the result (the closest point ID) and the squared distance in a tuple, like this:
point = [1.0, 2.0, 3.0]
kdtree = easy3d.KdTreeSearch_ANN(pc)
id = kdtree.find_closest_point(point)
id, sd = kdtree.find_closest_point_with_squared_distance(point)