Skip to content

Add Manifold::WindingNumber #4905

Add Manifold::WindingNumber

Add Manifold::WindingNumber #4905

Workflow file for this run

# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build_windows:
name: Windows (TBB:${{matrix.parallelization}}, SHARED:${{matrix.shared}})
timeout-minutes: 30
strategy:
matrix:
parallelization: [OFF, ON]
shared: [OFF, ON]
runs-on: windows-2025
steps:
- uses: actions/checkout@v6
- uses: lukka/get-cmake@v4.2.3
with:
cmakeVersion: 4.0.2
- &clone-tbb
uses: ./.github/actions/git-clone
with:
name: tbb
url: https://github.com/oneapi-src/oneTBB.git
tag: v2022.3.0
- &clone-clipper2
uses: ./.github/actions/git-clone
with:
name: clipper2
url: https://github.com/AngusJohnson/Clipper2.git
rev: 46f639177fe418f9689e8ddb74f08a870c71f5b4
- &clone-nanobind
uses: ./.github/actions/git-clone
with:
name: nanobind
url: https://github.com/wjakob/nanobind.git
tag: v2.12.0
- &clone-gtest
uses: ./.github/actions/git-clone
with:
name: gtest
url: https://github.com/google/googletest.git
tag: v1.17.0
- uses: ilammy/msvc-dev-cmd@v1
- name: Build ${{matrix.parallelization}}
shell: bash
run: |
cmake . \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_USE_BUILTIN_TBB=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
-DFETCHCONTENT_SOURCE_DIR_TBB=tbb \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
-DFETCHCONTENT_SOURCE_DIR_NANOBIND=nanobind \
-DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=gtest \
-A x64 -B build
cmake --build build --target ALL_BUILD --config Release
- name: Test dll location
if: matrix.shared == 'ON'
shell: bash
run: |
ls ./build/lib/Release
[ -f ./build/lib/Release/manifold.dll ]
[ -f ./build/lib/Release/manifoldc.dll ]
- name: Test
shell: bash
run: |
cp ./build/lib/Release/* ./build/bin/Release
./build/bin/Release/manifold_test.exe
- name: Export determinism meshes
if: matrix.parallelization == 'OFF' && matrix.shared == 'OFF'
shell: bash
env:
MANIFOLD_OBJ_HEX_FLOAT: 1
run: |
cp ./build/lib/Release/* ./build/bin/Release
bash ./scripts/export_determinism_meshes.sh build/bin/Release ./manifold_test.exe meshes-windows
- name: Upload determinism meshes (Windows)
if: matrix.parallelization == 'OFF' && matrix.shared == 'OFF'
uses: actions/upload-artifact@v4
with:
name: meshes-windows
path: meshes-windows/
build:
name: GCC ${{matrix.gcc}} (CrossSection:${{matrix.cross_section}}, TBB:${{matrix.parallelization}})
timeout-minutes: 45
strategy:
matrix:
cross_section: [ON]
parallelization: [OFF, ON]
os: [ubuntu-24.04]
gcc: [13, 14]
include:
- cross_section: OFF
parallelization: ON
os: ubuntu-24.04
gcc: 14
- cross_section: ON
parallelization: ON
os: ubuntu-22.04
gcc: 11
runs-on: ${{ matrix.os }}
env:
CC: gcc-${{ matrix.gcc }}
CXX: g++-${{ matrix.gcc }}
steps:
- uses: actions/checkout@v6
- &setup-python
uses: actions/setup-python@v5
with:
python-version: '3.x'
cache: 'pip'
- run: pip install -U trimesh pytest
- name: Install apt packages
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: libgtest-dev libassimp-dev git libtbb-dev pkg-config cmake
- *clone-clipper2
- *clone-nanobind
- name: Build
run: |
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_SHARED_LIBS=ON \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_PYBIND=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
-DFETCHCONTENT_SOURCE_DIR_NANOBIND=nanobind \
-DMANIFOLD_CROSS_SECTION=${{matrix.cross_section}} \
-DASSIMP_ENABLE=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
. -B build
cmake --build build
- name: Test
if: matrix.cross_section == 'ON'
run: |
./build/test/manifold_test
# python tests
export PYTHONPATH=$PYTHONPATH:$(pwd)/build/bindings/python
python3 bindings/python/examples/run_all.py -e
python3 -m pytest
- name: Export determinism meshes
if: matrix.parallelization == 'OFF' && matrix.gcc == 14 && matrix.os == 'ubuntu-24.04'
env:
MANIFOLD_OBJ_HEX_FLOAT: 1
run: |
bash ./scripts/export_determinism_meshes.sh build/test ./manifold_test meshes-linux
- name: Upload determinism meshes (Linux)
if: matrix.parallelization == 'OFF' && matrix.gcc == 14 && matrix.os == 'ubuntu-24.04'
uses: actions/upload-artifact@v4
with:
name: meshes-linux
path: meshes-linux/
- name: test cmake consumer
run: |
sudo cmake --install build
./scripts/test-cmake.sh
build_no_iostream:
name: NO_IOSTREAM (clang)
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install apt packages
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: cmake clang libgtest-dev
- name: Configure + build with MANIFOLD_NO_IOSTREAM=ON, MANIFOLD_TEST=ON
run: |
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DMANIFOLD_NO_IOSTREAM=ON \
-DMANIFOLD_USE_BUILTIN_CLIPPER2=ON \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_TEST=ON \
-DMANIFOLD_PYBIND=OFF \
. -B build
cmake --build build
- name: Run manifold_test (iostream-using TESTs are gated out)
run: ./build/test/manifold_test
- name: Verify conflict guard fires (NO_IOSTREAM + DEBUG)
run: |
if cmake -DMANIFOLD_NO_IOSTREAM=ON -DMANIFOLD_DEBUG=ON \
-DMANIFOLD_USE_BUILTIN_CLIPPER2=ON \
. -B /tmp/conflict-debug 2>&1; then
echo "FAIL: configure should have failed for NO_IOSTREAM + DEBUG"
exit 1
fi
build_gcc_codecov:
name: code coverage
timeout-minutes: 45
strategy:
matrix:
# parallelization: [OFF, ON]
parallelization: [OFF]
env:
CC: gcc-14
CXX: g++-14
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Install apt packages
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: libgtest-dev git libtbb-dev pkg-config lcov cmake
- *clone-clipper2
- name: build clipper2
run: |
cd clipper2/CPP
cmake -DCMAKE_BUILD_TYPE=Release . -B build
cmake --build build
sudo cmake --install build
- name: build
run: |
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_SHARED_LIBS=ON \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_PYBIND=OFF \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DMANIFOLD_CROSS_SECTION=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
-DCODE_COVERAGE=ON \
. -B build
cmake --build build
- name: Coverage Report
run: |
cd build
lcov --capture --gcov-tool gcov-14 --ignore-errors mismatch --initial --directory . --output-file ./code_coverage_init.info
test/manifold_test
lcov --capture --gcov-tool gcov-14 --ignore-errors mismatch --directory . --output-file ./code_coverage_test.info
lcov --add-tracefile ./code_coverage_init.info --add-tracefile ./code_coverage_test.info --output-file ./code_coverage_total.info
lcov --extract ./code_coverage_total.info "/*/manifold/src/*" --output-file ./code_coverage.info
- uses: codecov/codecov-action@v5
with:
disable_search: true
files: build/code_coverage.info
fail_ci_if_error: false
name: ${{matrix.parallelization}}
token: ${{secrets.CODECOV_TOKEN}}
verbose: true
build_wasm:
name: WASM (TBB:${{matrix.parallelization}}, DEBUG:${{matrix.debug}})
timeout-minutes: 30
runs-on: ubuntu-22.04
strategy:
matrix:
parallelization: [OFF, ON]
debug: [OFF, ON]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 25
cache: 'npm'
cache-dependency-path: bindings/**/package-lock.json
- name: Install apt packages
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: cmake
version: 1
- name: Setup EMSDK
uses: mymindstorm/setup-emsdk@v14
with:
version: 5.0.2
- *clone-tbb
- *clone-clipper2
- *clone-gtest
- name: Build WASM ${{matrix.parallelization}}
run: |
emcmake cmake \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
-DMANIFOLD_USE_BUILTIN_TBB=ON \
-DMANIFOLD_DEBUG=${{matrix.debug}} \
-DMANIFOLD_ASSERT=${{matrix.debug}} \
-DFETCHCONTENT_SOURCE_DIR_TBB=tbb \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
-DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=gtest \
. -B build
cd build
emmake make
- name: Test WASM
if: matrix.parallelization == 'OFF'
run: |
cd build/test
node ./manifold_test.js
- name: Run unit tests
if: matrix.parallelization == 'OFF'
run: |
cd bindings/wasm
npm ci
npm run build
npm test
- name: Isolated npm smoke test
if: matrix.parallelization == 'OFF'
run: |
set -ev -o pipefail
cd bindings/wasm
wasmpath=$(pwd)
npmtestpath=../npmtest
# Create an npm package.
npm ci && npm pack
# Install it in an empty directory.
mkdir -p ${npmtestpath} && cd ${npmtestpath}
npm install ${wasmpath}/manifold-3d*.tgz
cp ${wasmpath}/test/fixtures/npm/* .
# Positive case smoke test.
npx manifold-cad ./unitSphere.mjs ./unitSphere.glb && echo "Positive smoke test succeeded"
# Negative case smoke test.
npx manifold-cad ./unitSphereNoManifoldImport.mjs ./unitSphereNoManifoldImport.glb || echo "Negative smoke test failed as expected"
- name: Build manifoldCAD editor
if: matrix.parallelization == 'OFF'
run: |
cd bindings/wasm
npm run ci:editor
npm run build:editor
- name: Build WASM examples
if: matrix.parallelization == 'OFF'
run: |
cd bindings/wasm/examples
npm run ci:examples
npm run build:examples
- name: Build WASM documentation and site
if: matrix.parallelization == 'OFF'
run: |
cd bindings/wasm
npm run docs
npm run public
- name: Upload manifoldCAD editor, examples and documentation
uses: actions/upload-artifact@v4
if: github.event_name == 'push' && matrix.parallelization == 'OFF' && matrix.debug == 'OFF'
with:
name: wasmpublic
path: bindings/wasm/public/
retention-days: 90
overwrite: true
- name: Upload complete wasm build.
uses: actions/upload-artifact@v4
if: github.event_name == 'push' && matrix.parallelization == 'OFF' && matrix.debug == 'OFF'
with:
name: wasm
path: bindings/wasm/
retention-days: 90
overwrite: true
build_fuzzer:
name: fuzzer
timeout-minutes: 30
strategy:
matrix:
os: [ubuntu-24.04, macos-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v6
- name: Install apt packages
if: matrix.os == 'ubuntu-24.04'
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: libgtest-dev clang cmake
version: 1
- name: Install brew packages
if: matrix.os == 'macos-latest'
run: |
brew install googletest cmake
- *clone-clipper2
- uses: ./.github/actions/git-clone
with:
name: fuzztest
url: https://github.com/google/fuzztest.git
rev: f1e26613f66997aa09d3026762e275de22b2daae
- name: Build
run: |
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_FUZZ=ON \
-DMANIFOLD_PYBIND=OFF \
-DCMAKE_CXX_COMPILER=clang++ \
-DMANIFOLD_CROSS_SECTION=ON \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
-DFETCHCONTENT_SOURCE_DIR_FUZZTEST=fuzztest \
. -B build
ASAN_OPTIONS=detect_container_overflow=0 cmake --build build
build_sanitizer:
name: Sanitizer (ASan+UBSan)
timeout-minutes: 30
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Install apt packages
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: libgtest-dev libtbb-dev clang cmake
version: 1
- *clone-clipper2
- name: Build (clang + asan/ubsan)
run: |
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_SHARED_LIBS=ON \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_PYBIND=OFF \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DMANIFOLD_CROSS_SECTION=ON \
-DMANIFOLD_PAR=OFF \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS="-fsanitize=address,undefined" \
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
-DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined" \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
. -B build
cmake --build build
- name: Test (small sanitizer subset)
env:
ASAN_OPTIONS: detect_container_overflow=0
UBSAN_OPTIONS: print_stacktrace=1
run: |
./build/test/manifold_test --gtest_filter="Boolean.DeterminismSimpleSubtract:Boolean.DeterminismSimpleUnion:Boolean.DeterminismSimpleIntersect:Boolean.MultiCoplanar:Boolean.NonIntersecting:Manifold.MeshDeterminism"
build_mxe:
name: MXE (TBB:${{matrix.parallelization == 'ON'}})
timeout-minutes: 30
strategy:
matrix:
parallelization: [OFF, ON]
runs-on: ubuntu-latest
container: openscad/mxe-x86_64-gui:latest
steps:
- uses: actions/checkout@v6
- *clone-clipper2
- name: Build
run: |
export MXEDIR=/mxe
export MXE_TARGETS=x86_64-w64-mingw32.static.posix
export MXEDIR=$HOME/openscad_deps/mxe
export MXETARGETDIR=$MXEDIR/usr/$MXE_TARGETS
export PATH=/mxe/usr/bin:$PATH
export CMAKE=$MXE_TARGETS-cmake
$CMAKE \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_PYBIND=OFF \
-DMANIFOLD_CBIND=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
. -B build
$CMAKE --build build
build_mac:
name: MacOS (TBB:${{matrix.parallelization == 'ON'}}, shared lib:${{matrix.shared == 'ON'}}, ${{matrix.os}})
timeout-minutes: 30
strategy:
matrix:
parallelization: [OFF, ON]
shared: [OFF, ON]
# macos-15-intel: intel
# macos-latest: arm
os: [macos-15-intel, macos-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v5
with:
python-version: '3.x'
cache: 'pip'
- name: Install common dependencies
run: |
brew install googletest assimp cmake
pip install trimesh pytest
- name: Install TBB
if: matrix.parallelization == 'ON'
run: brew install tbb
- *clone-clipper2
- name: Build
run: |
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DMANIFOLD_PYBIND=ON \
-DASSIMP_ENABLE=ON \
-DMANIFOLD_PAR=${{matrix.parallelization}} \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
. -B build
cmake --build build
- name: Test
run: |
build/test/manifold_test
- name: Export determinism meshes
if: matrix.parallelization == 'OFF' && matrix.shared == 'OFF' && matrix.os == 'macos-latest'
env:
MANIFOLD_OBJ_HEX_FLOAT: 1
run: |
bash ./scripts/export_determinism_meshes.sh build/test ./manifold_test meshes-mac
- name: Upload determinism meshes (macOS)
if: matrix.parallelization == 'OFF' && matrix.shared == 'OFF' && matrix.os == 'macos-latest'
uses: actions/upload-artifact@v4
with:
name: meshes-mac
path: meshes-mac/
- name: test cmake consumer
run: |
sudo cmake --install build
./scripts/test-cmake.sh
- name: test pkg-config consumer
if: matrix.shared == 'ON'
run: |
LDFLAGS=-Wl,-rpath,/usr/local/lib ./scripts/test-pkgconfig.sh
build_mac_builtin_tbb:
timeout-minutes: 30
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v5
with:
python-version: '3.x'
cache: 'pip'
- name: Install common dependencies
run: |
brew install googletest cmake
pip install trimesh pytest
- *clone-tbb
- *clone-clipper2
- name: test cmake consumer subdir
run: |
export CLIPPER2=$(pwd)/clipper2
export TBB=$(pwd)/tbb
cd ..
./manifold/scripts/test-cmake-subdir.sh
- name: Build
run: |
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DMANIFOLD_STRICT=ON \
-DMANIFOLD_USE_BUILTIN_TBB=ON \
-DMANIFOLD_DEBUG=ON \
-DMANIFOLD_ASSERT=ON \
-DMANIFOLD_PYBIND=OFF \
-DMANIFOLD_PAR=ON \
-DFETCHCONTENT_SOURCE_DIR_TBB=tbb \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
. -B build
cmake --build build
- name: Test
run: |
./build/test/manifold_test
- name: test cmake consumer
run: |
sudo cmake --install build
./scripts/test-cmake.sh
LDFLAGS=-Wl,-rpath,/usr/local/lib ./scripts/test-pkgconfig.sh
build_nix:
timeout-minutes: 30
strategy:
matrix:
variant: [manifold-none, manifold-tbb, manifold-js, manifold-js-tbb, manifold3d]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: nix build -L '.?submodules=1#${{matrix.variant}}'
determinism_check:
name: Cross-platform determinism check
needs: [build, build_windows, build_mac]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Download Linux meshes
uses: actions/download-artifact@v4
with:
name: meshes-linux
path: meshes/linux
- name: Download macOS meshes
uses: actions/download-artifact@v4
with:
name: meshes-mac
path: meshes/mac
- name: Download Windows meshes
uses: actions/download-artifact@v4
with:
name: meshes-windows
path: meshes/windows
- name: Compare meshes across platforms
run: |
bash ./scripts/compare_artifact.sh meshes