diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml new file mode 100644 index 000000000..dfc5205ba --- /dev/null +++ b/.github/workflows/build_wheels.yml @@ -0,0 +1,23 @@ +name: Build + +on: [push, pull_request] + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04, windows-latest, macos-latest] + steps: + - run: git config --global submodule.fetchJobs 8 + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Build wheels + uses: pypa/cibuildwheel@v2.15.0 + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + diff --git a/.github/workflows/manifold.yml b/.github/workflows/manifold.yml index db5ec3df4..833bfac3b 100644 --- a/.github/workflows/manifold.yml +++ b/.github/workflows/manifold.yml @@ -199,3 +199,14 @@ jobs: submodules: recursive - uses: cachix/install-nix-action@v15 - run: nix build -L '.?submodules=1#manifold-${{matrix.variant}}' + + build_nix_python: + timeout-minutes: 30 + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: cachix/install-nix-action@v15 + - run: nix build -L '.?submodules=1#manifold3d' diff --git a/CMakeLists.txt b/CMakeLists.txt index c6c6f5075..cd640f10a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,9 @@ else() option(CMAKE_BUILD_TYPE "Build type" Release) endif() -set(MANIFOLD_FLAGS ${MANIFOLD_FLAGS} -O3) +if(NOT MSVC) + set(MANIFOLD_FLAGS ${MANIFOLD_FLAGS} -O3) +endif() if(EMSCRIPTEN) message("Building for Emscripten") diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index 53a565688..e86c119a3 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -15,16 +15,26 @@ project(python) add_subdirectory(third_party) -pybind11_add_module(manifold3d manifold3d.cpp) -target_link_libraries(manifold3d PRIVATE manifold) -target_compile_options(manifold3d PRIVATE ${MANIFOLD_FLAGS}) -target_compile_features(manifold3d PUBLIC cxx_std_17) -target_include_directories(manifold3d +set(module_name manifold3d) +pybind11_add_module(${module_name} manifold3d.cpp) +target_link_libraries(${module_name} PRIVATE manifold) +target_compile_options(${module_name} PRIVATE ${MANIFOLD_FLAGS} + -DMODULE_NAME=${module_name}) +target_compile_features(${module_name} PUBLIC cxx_std_17) +target_include_directories(${module_name} PRIVATE ${PYBIND11_DIR}/include ) -set_target_properties(manifold3d PROPERTIES OUTPUT_NAME "manifold3d") +set_target_properties(${module_name} PROPERTIES OUTPUT_NAME "${module_name}") +if(SKBUILD) install( - TARGETS manifold3d + TARGETS ${module_name} + LIBRARY DESTINATION ${SKBUILD_PLATLIB_DIR} + COMPONENT bindings +) +else() +install( + TARGETS ${module_name} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT bindings ) +endif() diff --git a/bindings/python/examples/extrude.py b/bindings/python/examples/extrude.py index 354b86c0f..5212f7fdf 100644 --- a/bindings/python/examples/extrude.py +++ b/bindings/python/examples/extrude.py @@ -1,4 +1,4 @@ -from manifold3d import CrossSection, FillRule +from manifold3d import CrossSection def run(): @@ -11,7 +11,7 @@ def run(): polygons = cross_section.to_polygons() polygon = polygons[0] if set(polygon) != set(polygon_points): - raise Exception(f"{polygon=} differs from {polygon_points=}") + raise Exception(f"polygon={polygon} differs from polygon_points={polygon_points}") # extrude a polygon to create a manifold extruded_polygon = cross_section.extrude(10.0) @@ -19,20 +19,20 @@ def run(): observed_volume = extruded_polygon.get_volume() expected_volume = 10.0 if abs(observed_volume - expected_volume) > eps: - raise Exception(f"{observed_volume=} differs from {expected_volume=}") + raise Exception(f"observed_volume={observed_volume} differs from expected_volume={expected_volume}") observed_surface_area = extruded_polygon.get_surface_area() expected_surface_area = 42.0 if abs(observed_surface_area - expected_surface_area) > eps: - raise Exception(f"{observed_surface_area=} differs from {expected_surface_area=}") + raise Exception(f"observed_surface_area={observed_surface_area} differs from expected_surface_area={expected_surface_area}") # get bounding box from manifold observed_bbox = extruded_polygon.bounding_box expected_bbox = (0.0, 0.0, 0.0, 1.0, 1.0, 10.0) if observed_bbox != expected_bbox: - raise Exception(f"{observed_bbox=} differs from {expected_bbox=}") + raise Exception(f"observed_bbox={observed_bbox} differs from expected_bbox={expected_bbox}") return extruded_polygon if __name__ == "__main__": - run() \ No newline at end of file + run() diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index e562d0549..7ce5a2078 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -38,7 +38,7 @@ std::vector toVector(const py::array_t &arr) { return std::vector(arr.data(), arr.data() + arr.size()); } -PYBIND11_MODULE(manifold3d, m) { +PYBIND11_MODULE(MODULE_NAME, m) { m.doc() = "Python binding for the Manifold library."; m.def("set_min_circular_angle", Quality::SetMinCircularAngle, diff --git a/flake.lock b/flake.lock index 47f6c17b3..c8d033603 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1689068808, - "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "lastModified": 1692799911, + "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", "owner": "numtide", "repo": "flake-utils", - "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", "type": "github" }, "original": { @@ -37,11 +37,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1691006197, - "narHash": "sha256-DbtxVWPt+ZP5W0Usg7jAyTomIM//c3Jtfa59Ht7AV8s=", + "lastModified": 1692734709, + "narHash": "sha256-SCFnyHCyYjwEmgUsHDDuU0TsbVMKeU1vwkR+r7uS2Rg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "66aedfd010204949cb225cf749be08cb13ce1813", + "rev": "b85ed9dcbf187b909ef7964774f8847d554fab3b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 30b501c17..ab96a4e72 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ }: pkgs.stdenv.mkDerivation { inherit doCheck; pname = "manifold-${parallel-backend}"; - version = "beta"; + version = "2.2.0"; src = self; nativeBuildInputs = (with pkgs; [ cmake @@ -101,6 +101,36 @@ cp {extras,wasm}/*.wasm $out/ ''; }; + # but how should we make it work with other python versions? + manifold3d = with pkgs.python3Packages; buildPythonPackage { + pname = "manifold3d"; + version = "2.2.0"; + src = self; + propagatedBuildInputs = [ + numpy + ]; + buildInputs = with pkgs; [ + tbb + ]; + nativeBuildInputs = with pkgs; [ + cmake + ninja + setuptools + scikit-build-core + pyproject-metadata + pathspec + pkg-config + ]; + checkInputs = [ + trimesh + ]; + format = "pyproject"; + dontUseCmakeConfigure = true; + doCheck = true; + checkPhase = '' + python3 bindings/python/examples/run_all.py + ''; + }; }; devShell = devShell { }; } diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..7c5d81934 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,93 @@ +[project] +name = "manifold3d" +version = "2.2.0" +authors = [ + { name="Emmett Lalish", email="elalish@gmail.com" }, +] +description = "Library for geometric robustness" +readme = "README.md" +classifiers = [ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: C++", + "Topic :: Multimedia :: Graphics :: 3D Modeling", +] +requires-python = ">=3.7" + +dependencies = [ + "numpy; python_version<'3.12'", + "numpy>=1.26.0b1; python_version>='3.12'" +] + +[project.urls] +"Homepage" = "https://github.com/elalish/manifold" +"Bug Tracker" = "https://github.com/elalish/manifold/issues" + +[build-system] +requires = ["scikit-build-core", "pybind11"] +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +cmake.minimum-version = "3.18" +sdist.exclude = [ + ".github", + "bindings/c", + "bindings/wasm", + "docs", + "extras", + "meshIO", + "samples", + "test", + "oneTBB", # we may have this when we build with cibuildwheel + "bindings/python/third_party/pybind11/tests/", + "src/third_party/clipper2/CPP/Examples/", + "src/third_party/clipper2/CPP/Tests/", + "src/third_party/clipper2/CSharp/", + "src/third_party/clipper2/Delphi/", + "src/third_party/clipper2/DLL/", + "src/third_party/clipper2/Tests/", + "src/third_party/glm/doc/", + "src/third_party/glm/test/", + "src/third_party/thrust/dependencies/cub/", + "src/third_party/thrust/dependencies/libcudacxx/.upstream-tests/", + "src/third_party/thrust/dependencies/libcudacxx/docker/", + "src/third_party/thrust/dependencies/libcudacxx/test/", + "src/third_party/thrust/dependencies/libcudacxx/docs/", + "src/third_party/thrust/dependencies/libcudacxx/libcxx/", + "src/third_party/thrust/dependencies/libcudacxx/libcxxabi/", + "src/third_party/thrust/dependencies/libcudacxx/libunwind/", + "src/third_party/thrust/dependencies/libcudacxx/utils/google-benchmark/", + "src/third_party/thrust/docs/", + "src/third_party/thrust/testing/", + "src/third_party/thrust/internal/test/", + "src/third_party/thrust/examples/", + "src/third_party/thrust/thrust/system/cuda", +] +wheel.packages = ["manifold3d"] +cmake.args = ["-DMANIFOLD_PAR=TBB", "-DMANIFOLD_TEST=OFF"] +install.components = ["bindings"] + +[tool.cibuildwheel] +build-frontend = "build" +test-requires = ["trimesh"] +test-command = "python {project}/bindings/python/examples/run_all.py" +# Setuptools bug causes collision between pypy and cpython artifacts +manylinux-x86_64-image = "manylinux_2_28" +musllinux-x86_64-image = "musllinux_1_2" +skip = ["*-win32", "*_i686", "pp*", "*-musllinux*"] + +# only clone TBB once +before-all = "git clone --depth 1 --branch v2021.10.0 https://github.com/oneapi-src/oneTBB.git" +[tool.cibuildwheel.config-settings] +"cmake.define.FETCHCONTENT_SOURCE_DIR_TBB" = "./oneTBB" +"cmake.define.FETCHCONTENT_UPDATES_DISCONNECTED" = "ON" + +[tool.cibuildwheel.macos] +archs = ["x86_64", "arm64"] +environment = "MACOSX_DEPLOYMENT_TARGET=10.14" +test-skip = "*-macosx_arm64 *-macosx_universal2:arm64" + +[tool.cibuildwheel.windows] +before-build = "pip install delvewheel" +repair-wheel-command = "delvewheel repair -w {dest_dir} {wheel}" diff --git a/src/cross_section/src/cross_section.cpp b/src/cross_section/src/cross_section.cpp index 8d41db74c..2f15371b6 100644 --- a/src/cross_section/src/cross_section.cpp +++ b/src/cross_section/src/cross_section.cpp @@ -291,7 +291,7 @@ std::shared_ptr CrossSection::GetPaths() const { if (transform_ == glm::mat3x2(1.0f)) { return paths_; } - paths_ = shared_paths(transform(paths_->paths_, transform_)); + paths_ = shared_paths(::transform(paths_->paths_, transform_)); transform_ = glm::mat3x2(1.0f); return paths_; } diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index be03c2601..01977b462 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -14,8 +14,6 @@ #include "impl.h" -#include - #include #include #include diff --git a/src/manifold/src/properties.cpp b/src/manifold/src/properties.cpp index 42dd6d37a..c775d7bda 100644 --- a/src/manifold/src/properties.cpp +++ b/src/manifold/src/properties.cpp @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include -#include - #include #include "impl.h" diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 13deab440..57c7c830a 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include #include #include diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt index 74807babf..6d51edf85 100644 --- a/src/utilities/CMakeLists.txt +++ b/src/utilities/CMakeLists.txt @@ -51,6 +51,7 @@ if(MANIFOLD_PAR STREQUAL "TBB") GIT_PROGRESS TRUE ) FetchContent_MakeAvailable(TBB) + set_property(DIRECTORY ${TBB_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) endif() target_compile_options(${PROJECT_NAME} INTERFACE -DMANIFOLD_PAR='T') if(TARGET TBB::tbb) diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index 42ad4c244..2085169bc 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -636,9 +636,9 @@ TEST(Boolean, BooleanVolumes) { // m7 = m1 + m2 + m3 auto m1 = Manifold::Cube({1, 1, 1}); auto m2 = Manifold::Cube({2, 1, 1}).Transform( - glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0, 0))); + glm::mat4x3(glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0, 0)))); auto m4 = Manifold::Cube({4, 1, 1}).Transform( - glm::translate(glm::mat4(1.0f), glm::vec3(3.0f, 0, 0))); + glm::mat4x3(glm::translate(glm::mat4(1.0f), glm::vec3(3.0f, 0, 0)))); auto m3 = Manifold::Cube({3, 1, 1}); auto m7 = Manifold::Cube({7, 1, 1}); @@ -906,4 +906,4 @@ TEST(Boolean, Sweep) { #endif PolygonParams().processOverlaps = false; -} \ No newline at end of file +} diff --git a/test/cross_section_test.cpp b/test/cross_section_test.cpp index 27c32d8cf..8fd5e42af 100644 --- a/test/cross_section_test.cpp +++ b/test/cross_section_test.cpp @@ -104,7 +104,7 @@ TEST(CrossSection, Transform) { 0.0f, 3.0f, 0.0f, // 0.0f, 0.0f, 1.0f); - auto b = sq.Transform(trans * scale * rot); + auto b = sq.Transform(glm::mat3x2(trans * scale * rot)); auto b_copy = CrossSection(b); auto ex_b = Manifold::Extrude(b, 1.).GetMesh(); diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index 96f6dfde8..15a94d97d 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -644,7 +644,7 @@ TEST(Manifold, Invalid) { auto invalid = Manifold::Error::InvalidConstruction; auto circ = CrossSection::Circle(10.); auto empty_circ = CrossSection::Circle(-2.); - auto empty_sq = CrossSection::Square(glm::vec3(0.0f)); + auto empty_sq = CrossSection::Square(glm::vec2(0.0f)); EXPECT_EQ(Manifold::Sphere(0).Status(), invalid); EXPECT_EQ(Manifold::Cylinder(0, 5).Status(), invalid);