[python] fix warp callback (#674)
* [python] fix warp callback I recently broke this making it a no-op due to the vec reference becoming a by-value copy in python callback. This fix provides a simple adapter like we had before allowing python to return modified values from the callback. * update torus_knot.py demo to expose both warp modes * add torus_knot.py to pytest * use pytest in github CI * add pytest to flake.nix
This commit is contained in:
@@ -23,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt install -y libglm-dev libgtest-dev libassimp-dev git libtbb-dev libthrust-dev pkg-config libpython3-dev python3 python3-distutils python3-pip lcov
|
||||
pip install trimesh
|
||||
pip install trimesh pytest
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
@@ -42,6 +42,7 @@ jobs:
|
||||
./manifold_test
|
||||
cd ../../
|
||||
python3 bindings/python/examples/run_all.py -e
|
||||
python3 -m pytest
|
||||
- name: Coverage Report
|
||||
# only do code coverage for default sequential backend, it seems that TBB
|
||||
# backend will cause failure
|
||||
|
||||
+20
-10
@@ -1,6 +1,6 @@
|
||||
# %%
|
||||
import numpy as np
|
||||
from manifold3d import *
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
# Creates a classic torus knot, defined as a string wrapping periodically
|
||||
# around the surface of an imaginary donut. If p and q have a common
|
||||
@@ -9,7 +9,7 @@ from manifold3d import *
|
||||
# handling of triangles.
|
||||
|
||||
|
||||
def run():
|
||||
def run(warp_single=False):
|
||||
# The number of times the thread passes through the donut hole.
|
||||
p = 1
|
||||
# The number of times the thread circles the donut.
|
||||
@@ -72,16 +72,26 @@ def run():
|
||||
m2[:, 3, 0] = majorRadius
|
||||
m3 = ax_rotate(2, psi)
|
||||
|
||||
v = v[:, None, :] @ (m1 @ m2 @ m3)
|
||||
return v[:, 0, :3]
|
||||
v = v[:, None, :] @ m1 @ m2 @ m3
|
||||
pts[:] = v[:, 0, :3]
|
||||
|
||||
def func_single(v):
|
||||
pts = np.array(v)[None, :]
|
||||
pts = func(pts)
|
||||
return tuple(pts[0])
|
||||
pts = np.array([v])
|
||||
func(pts)
|
||||
return pts[0]
|
||||
|
||||
return circle.revolve(int(m)).warp_batch(func)
|
||||
# return circle.revolve(int(m)).warp(func_single)
|
||||
if warp_single:
|
||||
return circle.revolve(int(m)).warp(func_single)
|
||||
else:
|
||||
return circle.revolve(int(m)).warp_batch(func)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("warp_single", [True, False])
|
||||
def test_warp(warp_single):
|
||||
m = run(warp_single=warp_single)
|
||||
assert m.volume() == pytest.approx(20785.76)
|
||||
assert m.surface_area() == pytest.approx(11176.8)
|
||||
assert m.genus() == 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -271,8 +271,14 @@ NB_MODULE(manifold3d, m) {
|
||||
return self.Rotate(v.x, v.y, v.z);
|
||||
},
|
||||
nb::arg("v"), manifold__rotate__v.c_str())
|
||||
.def("warp", &Manifold::Warp, nb::arg("warp_func"),
|
||||
manifold__warp__warp_func)
|
||||
.def(
|
||||
"warp",
|
||||
[](const Manifold &self,
|
||||
std::function<glm::vec3(glm::vec3)> warp_func) {
|
||||
// need a wrapper because python cant modify a reference in-place
|
||||
return self.Warp([&warp_func](glm::vec3 &v) { v = warp_func(v); });
|
||||
},
|
||||
nb::arg("warp_func"), manifold__warp__warp_func)
|
||||
.def("warp_batch", &Manifold::WarpBatch, nb::arg("warp_func"),
|
||||
manifold__warp_batch__warp_func)
|
||||
.def(
|
||||
@@ -610,8 +616,14 @@ NB_MODULE(manifold3d, m) {
|
||||
cross_section__mirror__ax)
|
||||
.def("transform", &CrossSection::Transform, nb::arg("m"),
|
||||
cross_section__transform__m)
|
||||
.def("warp", &CrossSection::Warp, nb::arg("warp_func"),
|
||||
cross_section__warp__warp_func)
|
||||
.def(
|
||||
"warp",
|
||||
[](const CrossSection &self,
|
||||
std::function<glm::vec2(glm::vec2)> warp_func) {
|
||||
// need a wrapper because python cant modify a reference in-place
|
||||
return self.Warp([&warp_func](glm::vec2 &v) { v = warp_func(v); });
|
||||
},
|
||||
nb::arg("warp_func"), cross_section__warp__warp_func)
|
||||
.def("warp_batch", &CrossSection::WarpBatch, nb::arg("warp_func"),
|
||||
cross_section__warp_batch__warp_func)
|
||||
.def("simplify", &CrossSection::Simplify, nb::arg("epsilon") = 1e-6,
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
glm
|
||||
ninja
|
||||
(python39.withPackages
|
||||
(ps: with ps; [ trimesh ]))
|
||||
(ps: with ps; [ trimesh pytest ]))
|
||||
gtest
|
||||
]) ++ build-tools;
|
||||
cmakeFlags = [
|
||||
@@ -74,6 +74,7 @@
|
||||
./manifold_test
|
||||
cd ../../
|
||||
PYTHONPATH=$PYTHONPATH:$(pwd)/build/bindings/python python3 bindings/python/examples/run_all.py
|
||||
PYTHONPATH=$PYTHONPATH:$(pwd)/build/bindings/python python3 -m pytest
|
||||
cd build
|
||||
'';
|
||||
};
|
||||
@@ -155,12 +156,14 @@
|
||||
];
|
||||
checkInputs = [
|
||||
trimesh
|
||||
pytest
|
||||
];
|
||||
format = "pyproject";
|
||||
dontUseCmakeConfigure = true;
|
||||
doCheck = true;
|
||||
checkPhase = ''
|
||||
python3 bindings/python/examples/run_all.py
|
||||
python3 -m pytest
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[pytest]
|
||||
testpaths =
|
||||
bindings/python/examples
|
||||
Reference in New Issue
Block a user